viernes, 21 de febrero de 2014

Directivas en AngularJS

Ayer estuve dando una charla en Directivas de AngularJS en un nuevo meetup de AngularJS Madrid.
Esta vez tuvo lugar en las oficinas de Google España, a quienes les agradecemos su apoyo.

Como otras veces os dejo la presentación a continuación.
Los fuentes de los ejemplos los pueden encontrar en:
https://github.com/gonzaloruizdevilla/directivas






jueves, 2 de enero de 2014

Clojure y Leiningen en Mac OS X

Después de jugar un poco con Racket (http://racket-lang.org/) y habituarme al uso de paréntesis y corchetes por doquier, he decido hacer algunas pruebas con Clojure (http://clojure.org/) con Leiningen (http://leiningen.org/) para la gestión de proyectos.

Instalarlo es sencillo si tienes brew:

brew install leiningen

Para entender como funcionan Leiningen, este tutorial está muy bien:

https://github.com/technomancy/leiningen/blob/preview/doc/TUTORIAL.md

En mis pruebas estoy usando Liberator para crear APIs REST.

jueves, 5 de diciembre de 2013

Servicios en AngularJS

El pasado lunes el grupo AngularJS de Madrid se reunió de nuevo en las instalaciones de MediaLab Prado. En esta ocasión, fui yo quien dio la charla  y el tema que traté fueron los servicios de AngularJS.

Os dejo aquí la presentación por si fuera de vuestro interés.
Los fuentes para la charla los podéis encontrar aquí:
https://github.com/gonzaloruizdevilla/angularjsmadridservicios


martes, 8 de octubre de 2013

Emacs, Mac OS X y teclados en español

Hace poco he empezado a utilizar Emacs (http://www.gnu.org/software/emacs/) para programar en ML (http://www.smlnj.org/). Tanto el editor como el lenguaje son nuevos para mi así que me viene bien para salir de la zona de confort y practicar cosas nuevas.

La cuestión es que al empezar a programar, en los primeros ejercicios, para seleccionar un elemento de una tupla se utiliza una almohadilla, por ejemplo, (#1 a) y (#2 a) seleccionan el primer y segundo elemento de la tupla respectivamente. El problema es que con M-3 (Alt-3) no me pintaba la almohadilla.

Para resolverlo hay que editar la configuración de Emacs que está en el fichero ~/.emacs y agregar las siguientes lineas, que resuelven el problema de la almohadilla y algún carácter más:


;; Modificadores de teclas para emacs con teclado español
(global-set-key (kbd "M-1") "|")
(global-set-key (kbd "M-2") "@")
(global-set-key (kbd "M-3") "#")
(global-set-key (kbd "M-º") "\\")
(global-set-key (kbd "M-ç") "}")
(global-set-key (kbd "M-+") "]")
(global-set-key (kbd "M-ñ") "~")

domingo, 15 de septiembre de 2013

Introducción a Git en Hellín

Ayer tuvimos la tercera reunión del Meetup de desarrolladores de Hellín y alrededores. Esta vez el tema fue Git, probablemente el mejor gestor de versiones distribuido que hay en el mercado y además de código abierto. Dimos una introducción a los gestores de versiones y estuvimos haciendo prácticas con Git, de forma local y contra cuentas en GitHub, tanto por línea de comando como al final con una herramienta como SourceTree de Attlasian (menos el linuxero, que todavía no tiene versión...)

El grupo sigue creciendo de forma modesta, pero es que en esta zona de España no hay la comunidad que se puede encontrar en grandes ciudades y hay que ir generando impulso poco a poco. Lo importante es que en cada nueva reunión viene gente nueva y eso es muy positivo. Es el único grupo que conozco que hay en la zona de Albacete y Murcia, así que si vivís u os movéis por esa zona, podéis apuntaros y si hay gente que conozcáis que pueda estar interesada, comentádselo también.

Como siempre, aquí os dejo la presentación, por si os pudiera ser de interés:


viernes, 6 de septiembre de 2013

Generator de Yeoman para AngularJS con Jade y ExpressJs



Yeoman (http://yeoman.io/) es un conjunto de herramientas para que hacer desarrollo web sea agradable y productivo. Utiliza "yo" para hacer scaffolding de proyectos, "grunt" para las tareas de arrancar servidores, compilar SASS o CoffeeScript, optimizar imágenes y todo lo que se te pueda ocurrir. Con "bower" puedes gestionar las dependencias de las librerías de cliente, como hace "npm" para proyectos de NodeJS o los pom.xml en proyectos Java con Maven.

AngularJS (http://angularjs.org/) es uno de los frameworks MVWhatever de moda. En mi opinión, es de lo mejor que se puede encontrar. Está muy bien pensado, con unas ideas fundamentales de arquitectura muy bien pensadas, es muy productivo, tiene unos tutoriales fantásticos con los que puedes empezar a trabajar después de dedicarle un par de horas y tiene una flexibilidad tremenda.

Jade (http://jade-lang.com/) es un lenguaje y motor de templating para que generar HTML sea productivo. Tanto es así, que en Adesis todos los que hacemos front lo usamos y cuando tenemos que escribir HTML a la antigua usanza para algún otro motor de templating es peor que un dolor de muelas. Ya hay ports para todos los demás lenguajes. Está hecho por desarrolladores front para desarrolladores front, de ahí que los problemas habituales que tenemos estén correctamente abordados.

ExpressJs (http://expressjs.com/) es un servidor para NodeJs donde puedes hacer maravillas con muy pocas lineas de código. En concreto implementar APIs REST, ya sea porque hagas implementaciones finales o porque tengas que simular alguna con la que te vayas a integrar es algo trivial.

Los más probable es que ya conocieses todas estas piezas si haces desarrollo front, ¿no?

En cualquier caso, Yeoman tiene unos "generadores" que son los que hacen el scaffolding de proyectos, y puedas arrancar un nuevo proyecto con todas sus piezas en su sitio en 30 segundos. Hay generadores para proyectos muchos frameworks MVWhatever, como BackboneJs, EmberJs, Polymer y por supuesto AngularJS.

Yo uso mucho el de AngularJS, pero como quiero generar el código HTML con Jade, una vez creado el proyecto, tengo que modificar las tareas de Grunt, y lo mismo para meter un servidor de ExpressJS que haga de backend. En este caso, hay que agregar un proxy al servidor de Yeoman que enganche contra una instancia de ExpressJS.

Tras la cuarta repetición, me auto dí una colleja por cansino, y decidí hacer un fork del generador de AngularJS para agregarle Jade y Express.

A diferencia de algunos generadores que vi por ahí (pero seguro que alguno hay como este que no encontré), cuando modificas un fichero de ExpressJs este servidor también se reinicia de forma automática.

Lo he publicado npm para que quien tenga mis mismas necesidades lo pueda usar. Como todo con nodejs, es sencillísimo de instalar y utilizar.

El servidor ExpressJS está en la carpeta "server" y si te apañas con ExpressJS, verás que hay un fichero routes.js. Vamos terreno conocido.

Las plantillas Jade están en "app/jade". Tampoco hay sorpresas por aquí :)

Instalación
El nombre del paquete es "angularexpress", así que sería:

npm install -g generator-angularexpress

Uso

Para crear un nuevo proyecto, vete a la carpeta donde vayas a trabajar y teclear:

yo angularexpress

(Yeoman detecta los generadores instalados porque son los paquetes de npm que empiezan por el prefijo "generator-" y para usarlos no hay que poner el prefijo)
A partir de aquí serán las preguntas típicas del generador de AngularJS más la de si quieres usar Jade (por defecto se usará).

Datos del proyecto
npm: angularexpress
https://npmjs.org/package/generator-angularexpress

Código fuente:
https://github.com/gonzaloruizdevilla/generator-angularexpress

¡Que lo disfrutéis!



lunes, 24 de junio de 2013

Introducción a NodeJs

Esta es la presentación que utilicé en el ultimo Meetup de Desarrolladores de Hellín sobre Introducción a NodeJs.


jueves, 9 de mayo de 2013

JavaScript Eficiente


Aquí os dejo otra presentación que preparé para un curso hace un par de meses sobre como programar JavaScript de manera eficiente. Espero que os guste.


Meetup: Código Limpio

Hace mucho que no pongo posts en el blog. Lo lamento, de veras, porque me gustaría poder sacar tiempo para escribir más. Pero mientras tanto, os dejo aquí la presentación que dí en el Meetup de Desarrolladores de Hellín y Alrededores sobre código limpio.

Esta fue la presentación con la que iniciamos el grupo y fue bastante agradable. La presentación tuvo lugar el 9 de mayo de 2013 en Hellín, en las oficinas de la FEDA (Federación de Empresarios de Albacete) y los costes de la sala financiados por Adesis.

La próxima presentación para el 1 de junio, será sobre NodeJs. Si no estais demasiado lejos de Hellín (Albacete?, Murcia?, Alicante?, Almería?, Valencia?) igual os apetece apuntaros.

Nos encontraremos de nuevo aquí:


Ver mapa más grande

Y por supuesto he aquí la presentación:

sábado, 9 de junio de 2012

RequireJS y módulos web

RequireJS (http://requirejs.org, npm:requirejs) es una librería para cargar módulos javascript. Veamos por qué resulta tan interesante esta librería según sus creadores (http://requirejs.org/docs/why.html)

El problema
  • Los sitios webs se están convirtiendo en aplicaciones web.
  • La complejidad del código crece junto con el sitio.
  • Ensamblar todos los módulos se vuelve cada vez más dificil.
  • El desarrollador quiere ficheros o módulos de javascript pequeños.
  • Para el despliegue queremos optimizar el código con pocas o una sola petición http.

La solución
Los desarrolladores web necesitamos una solución con:
  • algún tipo de #include/import/require.
  • la habilidad para cargar las dependencias anidadas.
  • que sea fácil de usar por un desarrollador y que además alguna herramienta pueda optimizar el despliegue.

APIs de carga de scripts
Lo primero es conseguir una API de carga de scripts. Algunas candidatas pueden ser:
  • Dojo: dojo.require("algun.modulo")
  • LABjs: $LAB.script("algun/modulo.js")
  • CommonJS: require("algun/modulo")

Todas ellas permiten cargar un módulo en algun/path/algun/modulo.js. Idealmente, elegiríamos la sintaxis CommonJS, ya que es la que se va a volver más común con el tiempo y queremos poder reutilizar código. 

También querríamos disponer de alguna sintaxis que permita cargar los ficheros de javascript de los que disponemos actualmente: un desarrollador no debería tener que reescribir todo su código javascript para obtener todos los beneficios de la carga dinámica de scripts.

Sin embargo, necesitamos algo que funcione bien en el navegador. La función require() de CommonJS es una tiene una llamada síncrona que espera que el módulo se obtenga inmediatamente. Esto es algo que no funciona bien con los navegadores.

Síncrono vs asíncrono
Este ejemplo debería ilustrar el problema básico para el navegador. Supongamos que tenemos un objeto Empleado y que queremos un objeto Gerente que derive de Empleado. Para este ejemplo, podríamos codificar algo parecido a esto con la API de carga de scripts:

var Empleado = require("types/Empleado");

function Gerente () {
  this.reportes = [];
}

//Error si la llamada es asíncrona
Gerente.prototype = new Empleado();
Como se indica en el comentario, si require() es asíncrono, este código no funcionará. Sin embargo, cargar scripts de manera síncrona puede acabar con el rendimiento del navegador. Por lo tanto, ¿qué se puede hacer?

Carga de scripts: XHR
Sin duda es tentador usar XMLHttpRequest (XHR) para la carga de scripts. Si se usase XHR, entonces podríamos revisar el código anterior: podríamos usar una expresión regular para encontrar llamadas a require(), asegurarnos de la carga de dichos scripts y luego usar eval() o etiquetas script en los que su cuerpo sería el texto del script cargado mediante XHR.

Usar eval() para evaluar es malo porque:

  • A algunos desarrolladores les han enseñado que eval() es malo
  • Algunos entornos no permiten eval()
  • Es muy difícil de depurar(). Firebug y el inspector de WebKit tienen una convención (//@sourceURL=) que permite dar un nombre al texto evaluado, pero no hay un soporte universal en todos los navegadores
  • el contexto de eval() es distinto entre los navegadores. Puedes usar execScript en IE para ayudar con este tema, pero esto implica gestionar más piezas distintas.

Usar tags script pasándoles el texto del fichero como el texto del cuerpo es malo porque:

  • Al depurar, el número de línea que recibes en un error no se corresponde con el del fichero original.

XHR tiene también problemas en peticiones cross-domain. Aunque algunos navegadores soportan ahora peticiones XHR cross-domain, el soporte sigue sin ser universal, y además los responsables de Internet Explorer decidieron exponer una API distinta para peticiones cross-domain, XDomainRequest. Más partes en movimiento y más cosas que pueden salir mal. En particular, necesitas asegurarte de no enviar cabeceras HTTP que no sean estándares o puede haber algunas peticiones "previas" para verificar que el acceso cross-domain está permitido.

Dojo ha usado con cargador basado XHR con eval() y, aunque funciona, ha sido una fuente de frustración para los desarrolladores. Dojo tiene un cargador cross-domain, pero requiere que los módulos sean modificados mediante un paso de construcción para usar una función "wrapper" o envolvente, de forma que los tags de script con src="" puedan usarse para cargar los módulos. Hay muchos casos límites y partes en movimiento que generan muchas cargas en en el desarrollador.

Si se ha de crear un cargador de scripts, se puede hacer mejor.

Carga de scripts: web workers
Los Web Workers pueden ser otra alternativa para cargar scripts, pero:
  • No tiene soporte en todos los navegadores
  • Es una API que funciona mediante el intercambio de mensajes y probablemente los scripts quieran interactuar con el DOM, por lo que que esto implicaría que el Web Worker se usaría para recuperar el texto del script pero luego se pasaría el texto a la ventana principal que a su vez usaría el eval() o una tag script para ejecutar el script. Esto presenta los problemas de XHR mencionados anteriormente.

Carga de scripts: document.write()
Se puede utilizar document.write() para cargar scripts: se pueden cargar script de otros dominios y se corresponde con el mecanismo habitual de los navegadores para consumir scripts, con lo que permite una depuración sencilla.

Sin embargo, como en el ejemplo de la sección "Síncrono vs asíncrono", no podremos ejecutar ese script directamente. Idealmente, conoceríamos las dependencias de require() antes de ejecutar el script, y nos aseguraríamos de que esas dependencias se cargasen antes. Pero en este caso no tenemos acceso al script antes de ejecutarlo.

Además, document.write() no funciona tras la carga de la página. Una forma fantástica para que se perciba rendimiento en un sitio web es cargar el código bajo demanda, a medida que el usuario lo necesite para su siguiente acción.

Finalmente, los scripts que se cargan mediante document.write() bloquean la renderización de la página. Esto es un gran obstáculo cuando se busca la mejor optimización de rendimiento.

Carga de scripts: head.appendChild(script)
Se pueden crear scripts bajo demanda y agregarlos a la cabecera de la página:

var head = document.getElementsByTagName('head')[0],
    script = document.createElement('script'); 

script.src = url;

head.appendChild(script);

En realidad, el caso real incluye algo más que lo que se muestra en el snippet, pero se trata de la idea básica. Esta aproximación tiene la ventaja sobre document.write() de que no bloqueará el renderizado de la página y funcionará tras la carga de la página. Sin embargo, sigue estando el problema de Sincrono vs Asíncrono: idealmente deberíamos conocer las dependencias de require antes de ejecutar el script y asegurarnos de que dichas dependencias se cargan antes.

Envolviendo las funciones
Hemos establecido que necesitamos conocer las dependencias y que hay que cargarlas antes de ejecutar nuestro script. La mejor forma para hacer esto es construir el nuestra API de carga de módulo con funciones que envuelvan el código. Esta es la manera:

define(
  //El nombre de este módulo 
  "types/Gerente",
 
  //El array de dependencias
  ["types/Employee"],
  
  //La función a ejecutar cuando se hayan cargado las dependencias. Los argumentos
  // de esta función es el array de dependencias indicado más arriba.
  function (Empleado) {

    function Gerente () {
      this.reportes = [];
    }

    //Esto ahora SI funciona
    Gerente.prototype = new Empleado();

    //devuelve la función de contrucción de Manager para que pueda ser usado por otros módulos.
    return Gerente;
  }
);

Y esta es la sintaxis usada por RequireJS. Hay también una sintaxis simplificada por si solo quieres cargar ficheros javascript que no definen módulos:

require(["algun/script.js"], function() {

  //Esta función se llama cuando se ha cargado algun/script.js

});

Este tipo de sintaxis se eligió por que es breve y permite al cargador utilizar el tipo de carga de head.appendChild(script).

La diferencia de la sintaxis normal de CommonJS se debe a la necesidad de funcionar bien en navegadores. Han habido sugerencias para que la sintaxis normal de CommonJS pudiera ser usada con el tipo de carga de head.appendChild(script) si un proceso del servidor transformase los módulos en un formato de transporte que tuviese una función envolvente.

Creo que es importante no forzar el uso de un proceso de servidor en tiempo de ejecución para transformar código:

  • la depuración se vuelve extraña, los números de línea no están sincronizados con la fuente puesto que el servidor injecta la función que envuelve al código.
  • implica más aparataje. El desarrollo de front-end debería ser posible solo con ficheros estáticos.


Podeis ver más detalles de las motivaciones de diseño y los casos de uso de este formato con funciones envolventes llamado Asynchronous Module Definition (AMD)  en esta página Why AMD? que espero traduciros pronto.


PD. Aquí tenéis una tabla comparativa relativamente actualizada y muy completa de cargadores de javascript: https://docs.google.com/spreadsheet/ccc?key=0Aqln2akPWiMIdERkY3J2OXdOUVJDTkNSQ2ZsV3hoWVE#gid=2


miércoles, 2 de mayo de 2012

Las comas primero, un buen estilo para JavaScript

Me gusta el estilo de comas primero en JavaScript. Principalmente por estos dos motivos:
  1. Reduce la complejidad visual del código, por quedar las partes de cada sentencia más estructuradas visualmente. Por tanto, también:
  2. Ayuda a encontrar errores.
Creo que el siguiente ejemplo es bastante ilustrativo:



Aviso: Limitaciones de este estilo

Existe un pequeño problema de este estilo, y te afectará si utilizas el REPL de node.js.

El REPL de node.js lee de línea en línea. Cuando lee una nueva línea intenta  ejecutar el código de la siguiente forma:
  1. Primero intenta ejecutar el código como si fuera una expresión. 
  2. Si eso falla, intenta ejecutar el código como una sentencia.
  3. Si eso también falla, entonces asume que necesita más input.
Veamos estos dos ejemplos

Al ejecutarlos, pasa lo siguiente:
$ node
> var a = 1
undefined
> ,b = 2
... ,c = 3;
...
> var a = 1,
... b = 2,
... c = 3;
undefined
>

En el primer caso, el REPL sigue pidiendo de manera indefinida y hay que hacer un Ctrl-C para salir. El segundo caso funciona correctamente.

Lo que pasa en el primer caso es lo siguiente. Una vez que el REPL lee la primera linea, intenta ejecutarla como una expresión y falla. A continuación, intenta ejecutarla como una sentencia y funciona. Una vez que se ha usado la primera linea, se intenta ejectuar la segunda linea como una expresión y falla. La intenta ejecutar como una sentencia y también falla. Falla porque la coma al principio de la línea da un error de sintaxis. Por lo tanto, pide más entradas. El proceso se repite con la siguiente línea y pasa lo mismo. Lo seguirá intentando de forma recurrente porque no hay manera de añadir algo al final que transforme el contenido que hay desde la segunda línea en adelante en una expresión o sentencia válida.

Sin embargo,habitualmente, el estilo con coma primero no será un problema con node.js por que se usará en ficheros se leen de golpe. 

domingo, 25 de marzo de 2012

Generar UUIDs aleatorios con sólo 111bytes de javascript

Introducción

Hoy vamos a ver un ejemplo de código diminuto que genera UUIDs aleatorios en el que se están aplicando muchos trucos y lecciones de javascript.  Primero introduciré el concepto de UUID para quien no lo tenga claro y luego desarrollaré el código.

Lo interesante de este diminuto código es analizar como evolucionó desde sus orígenes hasta la versión definitiva. Este código fue publicado en 140byt.es, aunque siguió cambiando tras su publicación.

La idea original es de Jed Schmidt (@jedschmidt , http://who.jed.is/ ) y fue mejorada gracias a las contribuciones de github:subzey, github:LeverOne y github:tsaniel

Vamos a hacer un uso importante de la función String.replace de javascript, así que te recomiendo que la repases en https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/replace sobre todo  la sección "Specifying a function as a parameter".

UUID

UUID es el acrónimo de Universally Unique Identifier o Identificador Universal Único y se trata de un estándar en software publicado por la Open Software Fundacion (OSF).

El objetivo que persiguen los UUIDs es permitir a sistemas distribuidos identificar información de forma única sin que sea precisa una coordinación central. En este contexto, la palabra única significa realmente "prácticamente única" más que "garantizadamente única". Dado que los identificadores tienen un tamaño finito es posible que dos elementos distintos compartan identificador. El tamaño y proceso de generación del identificador se seleccionan de manera que en la práctica las colisiones de identificadores sean suficientemente improbables. De esta forma, cualquiera puede crear un UUID y utilizarlo para identificar un elemento con la confianza razonable de que ese identificador no será generado de forma involuntaria por quien necesite identificar otro elemento. Esto permite que la información etiquetada con UUIDs se puedan combinar en una base de datos sin necesidad de resolver conflictos de identificadores.

Un UUID es un número de 16 bytes. En su forma canónica, un UUID se representa por 32 dígitos hexadecimales, separados en cinco grupos por guiones, en la forma 8-4-4-4-12, como por ejemplo: 550e8400-e29b-41d4-a716-446655440000.

En total hay  340,282,366,920,938,463,463,374,607,431,768,211,456 combinaciones para los UUIDs, casi nada :) .

En la forma canónica del UUID hay dos posiciones relevantes: xxxxxxxx-xxxx-Mxxx-yxxx-xxxxxxxxxxxx. Los bits más importantes de y indican la variante y para la especificación los dos bits más importantes deben tener los valores 1 0, con lo que los valores hexadecimales válidos para y son 8, 9, a y b.  Dentro de la variante cubierta por la especificación de la UUID hay cinco versiones que se identifican por el valor de M. Estas versiones son:

  • Direcciones MAC M = 1
  • DCE Security. M = 2
  • MD5 Hash. M = 3
  • UUIDs aleatorios. M = 4. Este es el que interesa en este caso, por lo que el formato del UUID será de la forma xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, donde y valdrá 8, 9, a o b, como ya hemos comentado.
  • SHA-1 Hash. M = 5
Implementación

El inicio

La primera versión y más fácil de entender:
function() {
  return
    "00000000-0000-4000-8000-000000000000"
    .replace(
      /0/g,
      function() {
         return(
           0 |
           Math.random() * 16 
         ).toString(16)
      }
    )
}

Vemos tres importantes elementos. Primero, tenemos la plantilla del UUID. Segundo, la expresión regular para seleccionar las posiciones con cero que deben reemplazarse por números aleatorios (/0/g) y, por último, la función que genera cada caracter hexadecimal aleatorio. En esta función es reseñable el truco para generar un entero entre 0 y 15.

Math.random()*16 genera un número aleatorio entre 0 y 16, con bastantes decimales. Para conseguir de manera rápida utilizamos la expresión (0|x). Esta expresión devuelve la parte entera de x, es equivalente a aplicar Math.floor. A continuación, obtenemos la expresión hexadecimal del entero con un .toString(16)

Compactar la plantilla

En la siguiente iteración se compacta la plantilla del UUID.

(         
    "" +         // concatenamos como cadena:
    1e7 +        //  10000000 +
    -1e3 +       // -1000 +
    -4e3 +       // -4000 +
    -8e3 +       // -80000000 +
    -1e11        // -100000000000,
)

Es decir, comparando las dos alternativas de plantilla se observa una clara reducción de longitud:

"00000000-0000-4000-8000-000000000000"
(""+1e7+-1e3+-4e3+-8e3+-1e11)  //10000000-1000-4000-8000-100000000000

Claro, que ahora la plantilla, traducida a cadena tiene unos y ceros que hay que modificar, con lo que toca cambiar la expresión regular agregando dos caracteres más de /0/g a /1|0/g

De momento el código ya va así:

function(){return(""+1e7+-1e3+-4e3+-8e3+-1e11).replace(/1|0/g,function(){return(0|Math.random()*16).toString(16)})}

Recursión

Mirando el código vemos que function aparece un par de veces y esto igual se puede reducir. Para ello, nos ayudamos de la recursión. La idea es utilizar el replace y en su segundo parámetro llamar de nuevo a la función. Luego los pasos son:

  1. Demos un nombre a nuestra función
  2. Apoyándonos en el segundo parámetro de replace llamaremos a nuestra función
  3. Ahora, nuestra función necesita de un parámetro que le proporcionará replace.
  4. Cambiamos la lógica de la función. Si recibe un parámetro es que se invoca desde el replace y ejecutamos la generación del número aleatorio y si no viene informado dejamos continuar con ejecutando el replace de la plantilla del UUID.
Es decir, deberíamos obtener algo como el siguiente código anotado.

function b(
  a                  // contenedor
){
  return a           // si se pasa el parametro
    ? (              // se devuelve
      0 |            // entero
      Math.random()  // aleatorio
      * 16           // entre 0 to 15
      ).toString(16) // en formato hexadecimal
    : (              // en caso contrario
      "" +           // la cadena concatenada:
      1e7 +          // 10000000 +
      -1e3 +         // -1000 +
      -4e3 +         // -4000 +
      -8e3 +         // -80000000 +
      -1e11          // -100000000000,
      ).replace(     // reemplazando
        /1|0/g,      // unos y ceros con
        b            // dígitos hex aleatorios
      )
}


La versión compacta, con un ahorro de diez bytes, quedaría así:
function b(a){return a?(0|Math.random()*16).toString(16):(""+1e7+-1e3+-4e3+-8e3+-1e11).replace(/1|0/g,b)}


Byte a byte

Como cada byte cuenta, ahora toca otro truco para ahorrar un solo byte. Para poder generar la plantilla del UUID hemos utilizado esta expresión:

""+1e7+-1e3+-4e3+-8e3+-1e11

Hemos utilizado el ""+ para forzar la concatenación de los números. Para poder ahorrar un byte nos apoyaremos en la característica que tienen los arrays de realizar un toString implícito al sumarle otro elemento. Es decir, lo dejaremos así:

[1e7]+-1e3+-4e3+-8e3+-1e11

Acabamos de ahorrar algo más de un 1% de código.

La funcionalidad incompleta

No sé si has caído en la cuenta, pero hasta ahora no lo hemos hecho bien del todo. El UUID debe tener el formato xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx, donde y valdrá 8, 9, a o b y, sin embargo, lo que está ocurriendo es que "y" siempre vale 8. Para completar el código este volverá a crecer. Como se suele decir: un pasito pa lante, dos pasitos pa trás.

Lo primero es localizar el 8 en la plantilla para trabajar con él. Para ello lo inmediato sería utilizar algo como /0|1|8/g en la expresión regular. A continuación, tendremos que distinguir el ocho del cero y del uno, pero si revisas la documentación de replace, podemos anticipar esta distinción en la propia expresión regular escribiéndola así: /0|1|(8)/g

Entonces, si cambiamos la definición de la función de b(a) a b(a,c), resultará que el parámetro c vendrá informado a null o a 8, con lo que tenemos la palanca para poder discriminar.

Ahora vamos a complicarnos un poco la vida, que remedio.

Si se trata de reemplazar un 1 o un 0, no hay que hacer nada, pero si se trata del 8, hay que hacer lo siguiente:
  1. Generar un número aleatorio entre 0 y 3
  2. Sumarle 8
  3. Pasarlo a hexadecimal
Vamos a intentar reaprovechar lo máximo posible, por lo que nos apoyaremos en el Math.random y el toString(16).

Para el primer paso, ¿cómo generar el aleatorio adecuado? Con el siguiente código:
Math.random() * 16 >>  c / 4

Analicemos las posibilidades:
  1. c = undefined. Es equivalente a c = 0, con lo que se genera un aleatorio entre 0 y 16, y se hace un shift a la derecha de cero bits, o sea, que se conserva la parte entera.
  2. c = 8. Sobre el aleatorio hacemos un shift a la derecha de dos bits, con lo que reducimos el valor a la cuarta parte, conservando un valor entre 0 y 3. Esto se debe a que el valor original en su forma binaria estaría entre 0000 y 1111 y si hacemos dos shifts a la derecha, el rango en su forma binaria quedará siempre entre 0000 y 0011, es decir, entre 0 y 3 como habíamos dicho. Ya tenemos la primera parte resuelta.
Para el segundo paso nos apoyamos en el "OR".

( c | Math.random() * 16 >>  c / 4 )

Si c = 8, estamos haciendo un OR entre 1000 del 8 y el 00xx del doble shift, el resultado es un valor entre 1000 y 1011 que es lo mismo que entre 8 y 11, o expresándolo de forma hexadecimal uno de 8, 9, a o b.


Recomponiendo el código quedaría así:
function b(
  a,                 // contenedor
  c                  // 8 o undefined
){
  return a           // si se pasa el parametro
    ? (              // se devuelve
      c |            // entero
      Math.random()  // aleatorio
      * 16           // entre 0 to 15
      >> c / 4   // o entre 8 y 11 si c = 8
      ).toString(16) // en formato hexadecimal
    : (              // en caso contrario
      "" +           // la cadena concatenada:
      1e7 +          // 10000000 +
      -1e3 +         // -1000 +
      -4e3 +         // -4000 +
      -8e3 +         // -80000000 +
      -1e11          // -100000000000,
      ).replace(     // reemplazando
        /0|1|(8)/g,  // unos y ceros con
        b            // dígitos hex aleatorios
      )
}

Ahora ya generamos los UUIDs correctamente

Y volvemos a avanzar. Más difícil todavía

Vamos a deshacernos del parámetro c y de cuatro bytes.
Si no hace falta c, la expresión regular se compacta a /[018]/g quitando un par de bytes, y otro par en la definición de la función al quedar de nuevo como b(a).

Para seguir manteniendo la funcionalidad, en vez de utilizar las propiedades de OR nos apoyaremos en XOR en la generación de números aleatorios:

...
  return a           // si se pasa el parametro a
    ? (              // se devuelve
      a ^            // entero
      Math.random()  // aleatorio
      * 16           // entre 0 to 15
      >> a / 4   // o entre 8 y 11 si a = 8
      ).toString(16) // en formato hexadecimal
...


Veamos como se hace la magia. Hay tres casos posibles para los valores de a.
  1. Para el caso a=0 obtenemos 0^Math.random()*16>>0/4, y como >>0/4 es lo mismo que >>0, funcionará igual que Math.floor, como ya hemos visto. En esta situación, 0^ no hace nada.
  2. Para el caso a=1 tenemos: 1^Math.random()*16>>1/4, y >>1/4 sigue siendo >>0. Aquí 1^ cambia el bit menos significativo, es decir, 0 y 1 se intercambian, 2 con 3, y así sucesivamente. El efecto neto es que seguimos generando números aleatorios de 0 a 15.
  3. Para el caso a=8, tenemos 8^Math.random()*16>>8/4, >>8/4 se convierte en >>2.
    El máximo número de Math.random()*16 en forma binaria es 1111, por lo que nos moveremos entre 0000 y 1111. La hacer el shift a la derecha de 2 bit, el máximo número de Math.random()*16>>2 es 0011, y el rango 0000-0011, como habíamos visto esto genera los números aleatorios entre 0-3. Finalmente, como el bit más significativo es SIEMPRE 0, 8^ es en la práctica lo mismo que 8|, lo que asegura que el rango empieza por 8 como antes del cambio. Es decir, obtenemos 8 + {0, 1, 2, 3}.

Y así conseguimos finalmente un código de 111bytes que genera UUIDs aleatorios:
function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[108]/g,b)}



Existe otra versión publicada por Alexey Silin (@LeverOne) que es cuatro bytes más corta y esta basada en iteración en lugar de en recursión. Tira mucho más de conceptos matemáticos. La tenéis aquí: https://gist.github.com/1308368






viernes, 23 de marzo de 2012

¿Qué es un polyfill?

Un "polyfill", también conocido como un "polyfiller", es una pieza de código o plugin que te permite trabajar con una tecnología que esperas que el navegador te proporcione de forma nativa.

Y me preguntarás: ¿esto no es un "shim"? Y estarás en lo cierto. Un "shim" es una pieza que intercepta una API de manera transparente, cambiando los parámetros, gestionando la operación directamente o redirigiéndola a otro sitio. Los "shims" se usan típicamente cuando una API cambia. Con un "shim" se puede conseguir, por ejemplo, que código nuevo pueda funcionar con una API antigua u obsoleta.

Por tanto, podemos decir que un "polyfill" es un "shim" pero centrado en proporcionar a navegadores legacy la compatibilidad con funcionalidades HTML5 y CSS3.

A continuación os presento un ejemplo de polyfill para ilustrar el concepto.

requestAnimationFrame

requestAnimationFrame es una nueva característica de los navegadores que permite indicarle al navegador que deseas realizar una animación. Básicamente lo que le dices con esta función al navegador es: "antes de pintar el siguiente frame en pantalla, aplica esta lógica del juego o procesa esta animación". El método recibe como argumento el callback que se tiene que invocar antes del repintado. Como te puedes imaginar, esta función viene genial para programar juegos en entorno web.

Las ventajas de utilizar requestAnimationFrame son varias:
  • Si queremos utilizar setInterval o setTimeout, para realizar una animación a una velocidad constante hay que estar recalculando contantemente la diferencia de tiempo transcurrido entre el último frame y el momento actual, porque el parámetro de tiempo que se pasa a estas funciones no se aplica estrictamente. Con requestAnimationFrame nos olvidamos de esto y conseguimos una tasa de refresco constante.
  • Gestionar tabs inactivas. Esta es una de las grandísimas ventajas que proporciona. Al permitir al navegador elegir el mejor intervalo entre frames, los usuarios podrían estar jugando a un juego muy intensivo en CPU y que al abrir otra pestaña o al minimizar la ventana el juego se pause, liberando recursos para otras tareas. El jsfiddle a continuación lo ilustra correctamente.

El uso de requestAnimationFrame sería en teoría tan sencillo como:



Los problemas de requestAnimationFrame son (al menos) estos dos:
  1. Navegadores antiguos. No existe por lo que hay que tirar de un setInterval o setTimeout.
  2. Navegadores actuales. La API no está estable por lo que es necesario añadir el dichoso prefijo de los navegadores.
Así que necesitamos un polyfill. En este caso, es tan sencillo como lo que ves en el siguiente gist. Nos abstraemos de las implementaciones de los navegadores y tenemos un fallback a setTimeout:



Si quieres una versión más precisa o inteligente de este polyfill, aquí tienes otra versión de Erik Möller, ingeniero de Opera: http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating. Básicamente, escoge el delay más adecuado entre 4ms y 16ms para intentar conseguir una tasa de refresco lo más parecida a 60fps y prepara también el método contrario cancelAnimationFrame. Aquí tienes un gist ligeramente optimizado sobre la versión del artículo: https://gist.github.com/2174491

¡Quiero más polyfills!

Pues estás de suerte, el equipo de Modernizr mantiene un pequeño índice de polyfills en:
https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills

Y, por si te animas, Addy Osmani (está en el equipo de Google desde hace un par de días) ha escrito esta guía sobre como escribir polyfills:
http://addyosmani.com/blog/writing-polyfills/



ACTUALIZACIÓN (25-mar-2012):
Basándome en un ejemplo de 140byt.es aquí te presento otro gist con un polyfill de requestAnimationFrame ultracompacto:




sábado, 3 de marzo de 2012

Atractor de Lorenz en 101bytes

El atractor de Lorenz es uno de los ejemplos más conocidos en la teoría del caos. Para los que no tengan muy claro de que va esto de la teoría del caos, como resumen muy somero se puede decir esta teoría trata de estudiar sistema deterministas (es decir, no aleatorios) que son extremadamente sensibles a las condiciones iniciales. Pequeñas variaciones en las condiciones iniciales (si hablamos de un sistema físico podrían ser posición, temperatura, velocidad, presión o cualquier otra variable relevante del modelo) implica grandes diferencias en el comportamiento observado, dificultando enormemente la predicción a largo plazo (como pasa al intentar predecir el tiempo dentro de un mes).

Volviendo al atractor de Lorenz, este fué estudiado por  Ed N. Lorenz, un meteorólogo al que le debe el nombre, alrededor de 1963. Este sistema deriva de un modelo simplificado de la convección de la atmósfera. También emerge de manera natural a partir de modelos de láseres y dinamos.

El atractor tiene este aspecto:
Vemos que la figura tiene a orbitar alrededor de dos puntos, dibujando una especie de ocho retorcido.

El atractor se expresa de manera habitual como tres ecuaciones diferenciales no lineales acopladas.

$$\frac{dx}{dt} = a (y - x) \\ \frac{dy}{dt} = x (b - z) - y \\ \frac{dz}{dt} = x y - c z $$
El comportamiento está parametrizado por las tres constantes de las ecuaciones  "a", "b" y "c". Un conjunto habitual de valores suele ser:
$$ a = 10 \\ b = 28 \\  c = 8 / 3 $$
Otro conjunto también bastante habitual es:
 $$ a = 28 \\ b = 46.92 \\ c = 4 $$

El parámetro "a"es conocido como el número de Prandtl y "b" como el número de Rayleigh.

La serie no llega nunca a un estado estable, sino que es un ejemplo de caos determinista, siempre cambiante. Al igual que ocurre en otros sistemas caóticos, el sistema de Lorenz es muy sensible a las condiciones iniciales. Dados dos estados iniciales, no importa lo cercan que estén uno del otro, antes o después acabarán divergiendo.

Encontré una solución para implementar el atractor de Lorenz con solo 101 bytes. Lógicamente, el sitio para encontrar algo así es 140byt.es, un portal donde se publican snippets de código javascript que quepan en un twit, o sea, de 140 o menos bytes. Aquí tenéis el código:


El mérito del código es de Martin Kleppe (@aemkei). En GitHub podéis ver muchos otros snippets curiosos de menos de 140 bytes (https://github.com/aemkei).

Aquí tenéis una versión del código anotado, que sin duda es algo más inteligible :) :



Aquí tenéis un fiddle en el que ver el atractor en acción. Se ha usado una visualización en 2D dibujando la coordenada Z como el tamaño de cada punto. VER JSFIDDLE CON EJEMPLO





En este otro ejemplo podeis ver dos atractores, en los que se ha modificado ligeramente una de las condiciones iniciales. Al principio, los dos atractores (azul y verde) evolucionan de manera parecida, pero llegado un punto, los comportamientos son totalmente diferentes. VER EJEMPLO DE LOS DOS ATRACTORES




UPDATE(06/03/2012): Actualizados los enlaces a los jsfiddle que estaban un poco bailados.

viernes, 3 de febrero de 2012

Múltiples instancias de Chrome

¿Quieres tener varias instancias de Chrome arrancadas simultáneamente y que sean completamente independientes?
Es decir, que te permitan, por ejemplo:
  • Tener historiales distintos
  • Cookies distintas
  • Es decir, por ejemplo, tener varias sesiones de Gmail abiertas simultáneamente sin que se peguen
  • Aplicaciones o extensiones de chrome distintas
  • Sesiones de Chrome distintas
Bien, pues esto resulta bastante sencillo. Solo hay que seguir los siguientes pasos:
  1. Crear una carpeta por cada instancia en paralelo que quieras crear. Por ejemplo, en windows, C:\chrome\perfil_1
  2. Haz una copia un acceso directo a Chrome y agregale el parámetro --user-data-dir con el valor del directorio. Por ejemplo:
C:\Users\MiUsuario\AppData\Local\Google\Chrome\Application\chrome.exe --user-data-dir=C:\chrome\perfil_1

Para que el trabajo con las distintas instancias no sea muy lioso, dos consejitos rápidos:

1. Cámbiale el icono al acceso directo. De esta forma, sabrás perfectamente cual  vas a arrancar en cada momento. Chrome ya viene con varios de serie que podemos utilizar:



En mi caso, el resultado de utilizar el dorado es tener una barra como esta (donde son los dos últimos son los que corresponden con dos perfiles de chrome, lógicamente):



2. Aplica un tema distinto a cada instancia. Así sabrás perfectamente cual estás usando en cada momento. Los puedes consultar en: https://chrome.google.com/webstore/category/themes?hl=es
Puedes ver aquí dos instancias arrancadas simultáneamente (una con un tema bastante "chillón"):





lunes, 23 de enero de 2012

Arquetipo Maven para proyectos con Hadoop

Últimamente, he tenido que realizar un proyecto con Hadoop. Para facilitar esta tarea tenemos a nuestra disposición un arquetipo maven que nos simplifica enormemente el trabajo en estos proyectos. Para comenzar con un proyecto maven para Hadoo solo tenemos que utilizar la siguiente línea de comandos:
mvn archetype:generate -DarchetypeCatalog=http://dev.mafr.de/repos/maven2/

Selecciona hadoop-job-basic y completa los datos según se vayan pidiendo (artifactId, groupId, version) y tendrás un proyecto con el ejemplo tradicional de Hadoop WordCount.

Genera el proyecto de la manera tradicional con maven:
mvn install

Una vez generado, el fichero interesante es el artifactId-version-job.jar. Este fichero está autocontenido, con lo ejecutarlo en Hadoop es bastante sencillo:
hadoop jar artifactId-version-job.jar argumentos



martes, 17 de enero de 2012

Depurar node.js con Google Chrome (o Webkit)

Chrome, el navegador de Google, tiene una fantástica herramienta de depuración para aplicaciones web. Esta herramienta es genial para ayudar a evaluar que puede estar pasando en el código javascript del navegador (para arrancarlo el acceso rápido es Ctrl+Mayús+I en Windows y ⌥⌘I en Mac)

Dado que nodejs utiliza el mismo motor de javascript V8 que Chrome, la conclusión lógica es intentar utilizar esta herramienta para depurar aplicaciones nodejs, ¿no? Bien, pues resulta que es posible y sencillísimo.

Nota: me gusta desarrollar con TDD, es decir, en general no me gusta utilizar el depurador para desarrollar. Si se puede evitar, mejor que mejor. Sin embargo, como verás más abajo, con el depurador puedes inspeccionar todas la librerías que utiliza tu aplicación nodejs, lo cual considero treméndamente interesante para entender que pasa más allá de tu código.

Veamos cómo:

1. Instalamos node-inspector
Node Inspector (npm: node-inspector) es un interfaz de depuración para nodejs para poder utilizar el inspector de Chrome.
Como lo utilizaremos para depurar cualquier aplicación de nodejs, lo instalamos de manera global:
npm install -g node-inspector

Para arrancar node-inspector y dejarlo en segundo plano ejecutamos:
node-inspector &

En la consola veremos algo como:
info  - socket.io started
visit http://0.0.0.0:8080/debug?port=5858 to start debugging

Sobre windows: para arrancar node-inspector tuve que poner la ruta completa y lanzarlo directamente con node. Hice una instalación en c:\node-inspector, con lo que quedó así:
node C:\node-inspector\node_modules\node-inspector\bin\inspector.js



2. Montemos una aplicación de ejemplo para depurar.
Para el ejemplo montaremos una aplicación sencillota con express.
npm install express

Creamos un servidor "hola mundo" en el fichero server.js:
var express = require('express'),
    app = express.createServer();
app.get('/', function(req, res){
    res.send('Hello World');
});
app.listen(3000);

3. Y a depurar...
Arrancamos el servidor en modo depuración:
node --debug server.js

Con Google Chrome accedemos a http://0.0.0.0:8080/debug?port=5858 ( http://127.0.0.1:8080/debug?port=5858 ).

Y veremos la consola:



Desde aquí podemos poner puntos de interrupción, evaluar expresiones, interaccionar con la consola, ver el stack de llamadas, etc.


Y podemos inspeccionar todos los ficheros que utiliza node para realizar las tareas, con lo que conseguiremos hacer desaparecer la "automagia" de node y trabajar sobre seguro.

El listado de scripts desplegado:



Fragmento de http.js:



Inspección de objetos (esta captura la saco desde mac, que las anteriores eran en windows :) ):





sábado, 31 de diciembre de 2011

Empezar con MongoDB en Mac OS X en dos minutos

1. Descargar e instalar
Instalar MongoDB en Mac OS X es tan trivial como rápido usando el gestor de paquetes Homebrew:
$ brew update
$ brew install mongodb

2. Crear directorio para los datos
Por defecto MongoDB almacenará los datos en /data/db, pero no crear el directorio, por lo que es necesario hacerlo de manera explícita:
$ sudo mkdir -p /data/db/
$ sudo chown `id -u` /data/db

3. Arrancar y conectarse al servidor
Lo primero es arrancar el servidor en un terminal:
$ mongod

Abrimos otra pestaña del terminal y arrancamos el shell de mongo, que se conecta por defecto a localhost:
$ mongo

Y probamos un par de comandos en MongoDB (guardar un documento y buscar):
> db.foo.save( { a : 1 } )
> db.foo.find()

martes, 27 de diciembre de 2011

Server-Side JavaScript Injection en node.js y NoSQL

Node.js está creciendo de manera exponencial. Su comunidad y el interés que suscita no para de crecer. Como ejemplo, se puede ver que node.js es el segundo proyecto más seguido en GitHub y poco le queda ya para ponerse el número uno.  No hay duda de que la flexibilidad y potencia de esta herramienta son su principal atractivo, pero en estas características se encuentra también el talón de Aquiles de muchas aplicaciones, puesto que pueden exponer importantes vulnerabilidades. Para ilustrar, concienciar y aprender a protegernos, he traducido (de aquella manera) este interesante whitepaper de Bryan Sullivan, del Adobe Secure Software Engineering Team.

Antecedentes: XSS
XSS es un acrónimo conocido en el entorno web. XSS significa Cross-Site Scripting, y es un mecanismo por el que se ejecuta código javascript arbitrario en un navegador que está visitando otro dominio. Esto supone una vulnerabilidad muy importante, por la que los "malos" son capaces de robar sesiones y suplantar identidades en las aplicaciones web afectadas (mediante el robo de información de cookies de sesión del navegador), pueden hacer phishing (introduciendo en el portal afectado pantallas de login que permita captura credenciales), captura de teclado, etc. Según la Open Web Application Security Project (OWASP), los ataques XSS suponen la segunda amenaza más importante en aplicaciones web (justo por debajo de inyecciones de SQL).

La vulnerabilidad es, además, demasiado común, con un porcentaje muy alto de sitios de internet que están afectados. Una de las razones de esta proliferación de la vulnerabilidad a XSS es que resulta muy sencillo introducirla accidentalmente. Pongamos el siguiente ejemplo de código que se utiliza para obtener la cotización de un valor:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
  if ((xhr.readyState == 4) && (xhr.status == 200)) {
    var informacionValor = eval('(' + xhr.responseText + ')');
    alert('La cotización actual de ' + informacionValor.nombre + 
            ' es $' + informacionValor.cotizacion + '€');      
    }
  }
  function realizarPeticion(ticker) {
    xhr.open("POST","servicio_cotizacion",true);
    xhr.send("{\"ticker\" : \"" + ticker + "\"}");
  }

El código parece bastante directo, pero la llamada a eval está introduciendo una vulnerabilidad potencial. Si un atacante fuese capaz de manipular la respuesta del servicio de cotización, podría inyectar código arbitrario mediante la llamada a eval, que ejecutaría el código en el contexto del navegador de la víctima. El ataque podría en ese momento extraer información de autenticación, cookies de session, manipular el dom para inducir al usuario a introducir datos, activar un keylogger, o utilizar el navegador para realizar peticiones arbitrarias al servidor del dominio como si fuese el usuario, etc.

Un nuevo vector de ataque: Server-Side Javascript Injection

Analicemos ahora un pedazo de código de javascript parecido. Está diseñado para leer peticiones JSON,  con la diferencia de que en este caso se ejecutará en el contexto de un servidor web con node.js.
var http = require('http');
http.createServer(function (request, response) {
  if (request.method === 'POST') {
   
  var data = '';
  request.addListener('data', function(chunk) { 
       data += chunk; });
   
  request.addListener('end', function() {
  var informacionValor = eval("(" + data + ")");
   recuperaCotizacionValor(informacionValor.ticker);
   …
});

La misma línea de código (ejecutar eval sobre los datos recibidos)  es la responsable de la vulnerabilidad frente a inyección de código en estas líneas y en el ejemplo de XSS. Sin embargo, en este caso los efectos son mucho más graves que la pérdida de las cookes de la víctima.

Para ilustradlo, veamos primero un mensaje legítimo, no malicioso. Podría ser como el siguiente:
{"ticker" : "SAN"}

La llamada a eval interpreta la siguiente línea:
({"ticker" : "SAN"})

Nada impide al atacante enviar su propio código javascript para que se evalúe en servidor:
response.end("success")

El código de servidor ejecutaría el comando inyectado y devolvería el texto "success" como el cuerpo de la respuesta HTTP. Sin un atacante envía esta request para probar el sistema y recibe "success" como respuesta, sabrá que el servidor puede ejecutar código javascript arbitrario, y entonces puede proceder a ataques más dañinos.

Denegación de servicio
Un ataque efectivo y sencillo de denegación de servicio se puede ejecutar simplemente enviando el comando:
while(1)

Este ataque hará que el servidor afectado use el 100% de su tiempo de procesador en procesar un bucle infinito. El servidor se colgará y será incapaz de procesar ninguna otra petición hasta que el administrador manualmente reinicie el proceso. Este ataque de DoS es tremendamente asimétrico, puesto que el atacante no tiene que ahogar al servidor con millones de peticiones; una única y diminuta petición hace todo el trabajo.

Otra alternativa de ataque DoS sería sencillamente salir o matar el proceso:
process.exit()
process.kill(process.pid)

Acceso al file system

Otro objetivo potencial de los atacantes es leer los contenidos de ficheros del sistema local. Node.js y muchas bases de natos NoSQL como CouchDB, usa la API CommonJS. El acceso al file system se soporta importando el módulo "fs" (mediante la instrucción require):
var fs = require('fs');

En cualquier momento de la ejecución se pueden agregar módulos, de manera que aunque el script originalmente no incluyese la referencia el módulo, el atacante puede agregar la funcionalidad simplemente incluyendo la instrucción require adecuada junto con el código de ataque.

Los siguientes ataques listarían los contenidos del directorio actual y superior respectivamente:
response.end(require('fs').readdirSync('.').toString())
response.end(require('fs').readdirSync('..').toString())

A partir de aquí, es bastante sencillo reconstruir la estructura completa del sistema de ficheros. Para acceder a los contenidos de un fichero sería tan sencillo como:
response.end(require('fs').readFileSync(filename))

La cosa resulta más grave, puesto que el atacante no solo puede leer los contenidos de los ficheros sino que puede escribir también. El siguiente ataque inserta la cadena "//hackeado!" al principio del fichero actualmente ejecutado (lógicamente, se pueden realizar cosas peores).
var fs = require('fs');
var ficheroActual = process.argv[1];
fs.writeFileSync(ficheroActual, '//hackeado!\n' + fs.readFileSync(ficheroActual));


Por último, señalaré que es posible crear ficheros arbitrarios en el servidor objetivo, incluidos ficheros ejecutables:
require('fs').writeFileSync(nombrefichero,data,'base64');

donde nombrefichero es el nombre del fichero resultante (por ejemplo, "foo.exe") y data sería el contenido del fichero codificado en base-64. El atacante ya solo necesitará ejecutar este fichero, como ilustraré a continuación.

Ejecución de ficheros binarios

Una vez que el atacante puede escribir ficheros binarios en el servidor, necesita ejecutarlos. Una inyección de javascript como la siguiente ilustra como puede hacerlo:
require('child_process').spawn(nombrefichero);

A partir de este punto, los límites del atacante están en su imaginación.

Inyección NoSQL
Las vulnerabilidades de inyección de código javascript no están limitadas solo a llamadas de eval dentro de scripts de node.js. Los motores de bases de datos NoSQL que procesen código javascript  también pueden ser vulnerables. Por ejemplo, MongoDB soporta el uso de funciones de javascript en las query y en operaciones de map/reduce. Puesto que las bases de datos MongoDB (igual que otras NoSQL) no tienen definidos esquemas estrictos, los desarrolladores pueden utilizar código javascript para realizar querys arbitrariamente complejas que consulten estructuras de documentos dispares.

Por ejemplo, supongamos que tenemos una collección de MongoDB que contiene documentos que representan libros, otros que representan peliculas y otros que representan libros. Esta query en javascript seleccionará todos los documentos de cada una de las colecciones que fuesen escritos, rodados o grabados en el año especificado:

function() {
  var anio_busqueda = input_value;

  return this.anioPublicacion == anio_busqueda||
         this.anioRodaje == anio_busqueda||
         this.anioGrabacion == anio_busqueda;
}

Si la aplicación estuviese programada en PHP el código fuente podría parecerse al siguiente:

$query = 'function() { '.
         '  var search_year = \'' . $_GET['anio'] . '\';' .
         '  return this.anioPublicacion == anio_busqueda || ' .
         '         this.anioRodaje == search_year || ' .
         '         this.anioGrabacion == search_year; ' . 
         '}';

$cursor = $collection->find(array('$where' => $query));

Este código utiliza el parámetro "anio" de la petición como el parámetro de búsqueda. Al igual que en la vulnerabilidad tradicional de inyección de SQL, cuando la query se realiza de manera ad-hoc, es decir, concatenando la query directamente con el input del usuario, el código es vulnerable a un ataque de inyección de código de javascript en servidor. Este ejemplo sería un ataque bastante efectivo de denegación de servicio DoS contra el sistema
http://server/app.php?anio=1995';while(1);var%20foo='bar

Inyección NoSQL ciega
Otro posible vector de ataque cuando se utilizan inyecciones SSJS contra bases de datos NoSQL es el uso de injecciones ciegas NoSQL para extraer los contenidos la base de datos. Para demostrar como funciona este ataque continuaré con el ejemplo de MongoDB utilizado anteriormente.

Para ejecutar un ataque de inyección ciego, el ataque necesita determinar la diferencia entre una condición verdadera y otra falsa en el servidor. Esto es trivial con una inyección SSJS, más incluso que con la clásica inyección sql “OR 1=1” :
http://server/app.php?anio=1995';return(true);var%20foo='bar
http://server/app.php?anio=1995';return(false);var%20foo='bar

Si existe alguna diferencia entre las respuestas de estas dos inyecciones, entonces el atacante solo necesita realizar preguntas del tipo cierto/falso, y con un número suficiente de preguntas será capaz de extraer todos los contenidos de la base de datos. Veámoslo.

La primera pregunta que hay que responder es cuantas colecciones existen en la base de datos, o más preciesamente, si hay exactamente una colección en la base de datos, o si hay exactamente dos colecciones, etc:
return(db.getCollectionNames().length == 1);
return(db.getCollectionNames().length == 2);
…

Una vez que el atacante ha establecido cuantas colecciones existen, el siguiente paso será obtener sus nombres. Se chequeará cada nombre de colección en el array, primero para determinar la longitud del nombre y después para el nombre mismo, probando un carácter cada vez:
return(db.getCollectionNames()[0].length == 1);
return(db.getCollectionNames()[0].length == 2);
…
return(db.getCollectionNames()[0][0] == 'a');
return(db.getCollectionNames()[0][0] == 'b');

Una vez que se han extraido los nombres de las colecciones, el siguiente paso consiste en recuperar la colección de datos. De nuevo, lo primero que el atacante necesita hacer es determinar cuantos documentos hay en cada colección. Si el nombre de la primera colección fuese "foo":
return(db.foo.find().length == 1);
return(db.foo.find().length == 2);
…

En un ataque SQL ciego tradicional, el siguiente paso sería determinar la estructura de columnas de cada tabla. Sin embargo, este concepto de de estructura de columnas no tiene sentido en documentos NoSQL, que carecen de un esquema común. Cada documento en una colección puede tener una estructura distinta del resto de documentos. Sin embargo, este hecho no impide la extraccción de los contenidos de la base de datos. El atacante simplemente llamaría al método "tojsononeline" (http://api.mongodb.org/js/1.5.3/symbols/_global_.html#tojsononeline)  para devolver el documento como un string de JSON, calcular su longitud  y extraer un carácter cada vez:
return(tojsononeline(db.foo.find()[0]).length == 1);
return(tojsononeline(db.foo.find()[0]).length == 2);
…
return(tojsononeline(db.foo.find()[0])[0] == 'a');
return(tojsononeline(db.foo.find()[0])[0] == 'b');
…

Al final, con este método se recuperarían todos los contenidos de cada documento de cada colección en la base de datos.

Conclusiones y prevención
En los ejemplos anteriores, se ha visto que la vulnerabilidad de inyección de javascript en servidor se parece más a las técnicas tradicionales de inyección de SQL que a las de cross-site scripting. Las inyecciones de SSJS no necesitan de la ingeniería social de una víctima intermedia de la forma que se hace habitualmente con XSS, sino que el ataque se realiza directamente con peticiones HTTP arbitrarias. Por este motivo los mecanismos de defensa son similares de los de inyecciones de SQL:
  • Evitar generar comandos de javascript "ad-hoc" mediante la concatencación de script con datos de proporcionados por el usuario.
  • Validar los datos del usuario en comandos SSJS con expresiones regulares.
  • Evitar el uso del comando eval. En particular, al parsear JSON, usar alternativas mucho más seguras como JSON.parse.