Novedades en Django 1.3

Hace apenas una semana salio a la luz la versión 1.3 del framework de programación web Django.

Han sido varios meses de desarrollo y, fruto de ello, se han incorporado muchísimas novedades de gran importancia. Vamos a repasar en este artículo algunas de ellas.

Vistas basadas en clases

Hasta ahora las vistas se tenían que crear como funciones normales y corrientes. Aunque esto era más que suficiente, gracias a las nuevas vistas basadas en clases podremos definir vistas genéricas, y heredar otras a partir de ellas, reutilizando código.

Usarlas es muy simple. No hay más que crear una nueva clase que herede de la vista que queramos usar en cuestión. Django nos provee unas cuantas que posiblemente cumplan de sobra todas nuestras necesidades.

Por ejemplo, tenemos TemplateView, que es una vista que se encarga de cargar un template directamente (análogo al direct_to_template que teníamos antes). Para usarlo, podemos heredar de ella, y cambiar el template que tiene que cargar.

La página que carga la licencia de este mismo blog (es un HTML estático), podría estar declarada de la siguiente forma

from django.views.generic import TemplateView

class LicenciaView(TemplateView):
    template_name = "licencia.html"

Por su lado, el urls.py sería el siguiente:

from django.conf.urls.defaults import *
from blog.views import LicenciaView

urlpatterns = patterns('',
    (r'^about/license/', LicenciaView.as_view()),
)

Vemos que para cargar la vista tenemos que usar el método as_view, el cual, por cierto, nos ahorraría tener que heredar de la clase si lo único que vamos a hacer es sobrescribir atributos. En el ejemplo anterior, nos podríamos ahorrar el código en el views.py con lo siguiente:

from django.conf.urls.defaults import *
from django.views.generic import TemplateView

urlpatterns = patterns('',
    (r'^about/license/',
          TemplateView.as_view(template_name="licencia.html")),
)

Además podemos modificar el comportamiento de estas vistas de muchísimas otras formas, ya sea modificando el queryset que ejecuta, cambiando el nombre de la variable de contexto que tendrá el objeto principal o añadiendo nuevas variables de contexto que vayamos a necesitar (por poner algunos ejemplos).

class ArticulosView(ListView):
    context_object_name = "articulos"
    template_name = "articulos_list.html",

    def get_queryset(self):
        self.tag = get_object_or_404(Tag, name=self.args[0])
        return Articulo.objects.filter(tag=self.tag)

    def get_context_data(self, **kwargs):
        context = super(ArticulosView, self).get_context_data(**kwargs)
        context['tag'] = self.tag
        return context

El uso de estas clases genéricas puede llegar a ser mucho más complejo, dándonos muchísima más potencia que las anteriores vistas genéricas. Dado que podría dar para otro artículo entero, recomiendo leer la documentación oficial para entenderlas mejor.

Logging

En esta nueva versión de Django se incluye la posibilidad de realizar el logging del portal mediante el módulo oficial de Python.

Este módulo está compuesto por cuatro elementos básicos.

Logger
Este elemento identifica el recipiente donde se van a guardar todos los mensajes.
Handler
Una vez se genera un mensaje de error en el logger, este se ha de enviar a algún sitio. Estos lugares son los distintos handlers, que pueden ser la pantalla, un fichero del sistema, ...
Filters
Permiten filtrar que mensajes se mandan a cada uno de los handlers (podemos querer que solo alguno de ellos se muestren por pantalla, y que el resto se guarden en un fichero, por ejemplo).
Formatter
Define el formato de los mensajes.

Los mensajes tienen un nivel de criticidad, siendo los predeterminados DEBUG, INFO, WARNING, ERROR y CRITICAL. Estos niveles nos sirven, aparte de para clasificarlos, para poder restringirlos desde los loggers y handlers. Esto es así ya que ambos permiten indicar a partir de que criticidad admiten pasar los mensajes a través de ellos.

Para usar este módulo de logging desde Django, basta con generar el mensaje que queramos. Por ejemplo, si queremos guardar el momento en el que se entra en una vista en particular:

import logging
logger = logging.getLogger(__name__)

def mi_vista(request):
    logger.info('Hemos entrado en mi_vista')

Como podemos ver, a la hora de crear el logger hay que darle un nombre. Como estándar, se usa el del módulo en el que se está creando (referenciado por la variable __name__).

A continuación, ya sólo nos faltaría configurar los elementos anteriores. Esto se hace desde el settings.py, y puede a llegar a ser tan complejo como queramos (podemos añadir tantos loggers, handlers, filters y formatters como queramos).

Un ejemplo de esta configuración podría ser la siguiente:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': True,
    'formatters': {
        'simple': {
            'format': '%(levelname)s: %(message)s'
        },
    },
    'handlers': {
        'console':{
            'level':'INFO',
            'class':'logging.StreamHandler',
            'formatter': 'simple'
        },
    },
    'loggers': {
        'proyecto.app': {
            'handlers': ['console'],
            'level': 'DEBUG'
        }
    }
}

En este ejemplo estamos creando lo siguiente:

  • Un formatter que escupe la información con la siguiente pinta: NIVEL: mensaje
  • Un handler que imprimirá los mensajes con criticidad INFO o superior (es decir, todos excepto los de debug) por la salida estándar (stdout).
  • Un logger llamado proyecto.app, que usará los elementos descritos previamente.

Y listo, nuestro sistema ya está funcionando correctamente.

Manejo de ficheros estáticos

Hasta ahora manejar los ficheros estáticos (CSS, JavaScript, imágenes, ...) era algo complicado en Django. Usualmente lo que se hacía era usar la variable MEDIA_ROOT del settings.py, y se colgaba en el directorio al que apuntaba todo el contenido, para a continuación, configurar el servidor web en cuestión para que sirviese ese directorio estáticamente. A esto había que añadirle el estar pendiente de que si usamos alguna aplicación de terceros que también tiene ficheros estáticos, hay que recolectarlos y colgarlos junto a los nuestros.

Este método tiene varios problemas.

  • Hay que guardar bajo la misma ruta los ficheros estáticos de la web, y los ficheros subidos por los usuarios del portal (ya que también se suele usar la variable MEDIA_ROOT para marcar el directorio raíz donde se guardan estos).
  • No hay forma de que las distintas aplicaciones autocontengan todo su contenido estático. Si descargamos alguna que necesite de, por ejemplo ficheros CSS o imágenes (algo muy común), tendremos que coger esos ficheros y colgarlos fuera de la carpeta de esa aplicación, dentro de nuestro MEDIA_ROOT.

Por esta y otras razones, Django ha incorporado una aplicación dentro de django.contrib llamada staticfiles, que justamente arregla todos estos males, aparte de añadir otros beneficios, como facilitar el servir los ficheros estáticos desde un servidor dedicado a ello.

Esta nueva aplicación añade entre otras cosas un nuevo comando al manage.py, llamado collectstatic, que se encarga de recolectar los ficheros estáticos de todas las aplicaciones instaladas y situarlos en una carpeta designada mediante una variable del settings.py. Así, de esta manera, se pude configurar el servidor web para que sirva esa carpeta de forma estática.

De igual manera, se han añadido nuevas variables de entorno a los templates para definir las rutas de los ficheros estáticos: STATIC_URL y STATIC_ROOT, manteniendo las anteriores MEDIA_URL y MEDIA_ROOT para los ficheros subidos por parte de los usuarios.

Mejoras de templatetags

Se han realizado mejoras en ciertos templatetags.

  • El tag include pasa a permitir un parámetro with mediante el cual añadir nuevas variables de contexto a la hora de cargar el fichero; y un parámetro only para indicar que solo se quieren usar las variables de contexto definidas por el with anterior (y no el resto de las existentes en el entorno en ese momento).
  • El tag with pasa a poder definir varias variables de contexto al mismo tiempo. Esto evita el tener que usar X bloques anidados de withs (donde X podía llegar a tender a mucho ;) ).
  • El tag load permite el argumento from permitiendo cargar solo ciertos templatetags de cierto módulo (y no todos, como actualmente se hacía).

Y mucho más

Y hasta aquí algunos de los cambios grandes que recibe esta nueva versión. Me dejo muchos en el tintero (gran mejora en el módulo de cachés, configuración del comportamiento del borrado en cascada, mejora del módulo de testing unitario, ...), así como otros muchísimos cambios menores y bugs solucionados, pero en algún momento había que acabar.

Para los que sigan teniendo curiosidad, recomiendo leerse la lista entera de cambios, en la web oficial de Django.

Licencias en Android (ALVL)

El mercado de los móviles está en alza, y prueba de ello es la cantidad de aplicaciones para iPhone y Android que se descargan todos los días.

Si habéis programado alguna vez para Android y os habéis planteado el vender vuestra aplicación muy posiblemente os habréis preguntado como securizarla minimamente para evitar su uso indebido.

En Android las aplicaciones se suelen distribuir mediante el Market, que no es más que una tienda de aplicaciones desde la cual los usuarios pueden elegir una e instalarla en su terminal. El Market, en el proceso de descarga hace algo tan simple como coger el .apk (extensión de las aplicaciones de Android) que se genera al compilar la aplicación y llevársela al móvil del usuario.

Esto, a poco que pensemos un poco, veremos que nos va a plantear serios problemas si queremos rentabilizar nuestra aplicación. Y es que, si el usuario coge ese apk que ha instalado en su teléfono y lo distribuye por internet, cualquier persona podrá hacerse con nuestra aplicación de pago de forma gratuita.

Que sea tan simple piratear una aplicación en Android hace que el mercado negro esté al alza, por lo que gran parte de la comunidad desarrolladora pidio a Google que buscase alguna solución al problema.

Y Google aparecio, creando la Android License Verification Library, una librería que decía acabaría con el pirateo de aplicaciones.

Android License Verification Library

El funcionamiento de esta librería es muy sencillo de entender.

Google proporciona un mecanismo de autenticación de licencias. Mediante este, un desarrollador puede comprobar si el usuario que está ejecutando la aplicación ha comprado previamente una licencia de la misma.

Como bien sabrán los que usan Android, para poder acceder al Android Market se necesita una cuenta de Google. Es con esta mediante la cual se compran aplicaciones de pago, quedando estos programas asociados a la cuenta de Google en cuestión. Gracias a esta información Google es capaz de comprobar que el usuario que está ejecutando una aplicación la haya pagado previamente.

Este sistema no ofrece nada realmente nuevo. La diferencia, está en el modo en el que funciona internamente. En un principio para usar un sistema como este, todas las aplicaciones tendrían que pedir acceso a las cuentas de Google, acceso a la red, y demás peticiones de seguridad (esas que pocos usuarios miran antes de instalar una aplicación).

Para evitar esto, Google implementa esta librería mediante un servicio IPC entre la aplicación cliente, y la aplicación del Android Market.

|filename|images/0002-licencias-android-alvl/licensing_arch.png

Es decir, mi aplicación, que usa correctamente la librería, realiza una petición de certificación al Android Market (el que tiene instalado localmente el usuario) mediante un Binder. El Android Market, que tiene acceso a las cuentas de usuario del sistema, solicita a Google que compruebe si el usuario ha comprado verdaderamente la aplicación. Google le manda la respuesta al Android Market, y es este, mediante el Binder anterior, el que se encarga de notificarle la respuesta a la aplicación cliente.

Esta aplicación, con esta respuesta, podrá actuar en consecuencia. Sea bloquear el acceso a la aplicación, disminuir sus capacidades, o simplemente mostrar un mensaje regañando al usuario.

Por último, y para evitar alteraciones en la respuesta, Google la firma con un par de claves RSA que el programador ha generado previamente desde su cuenta de desarrollador en el market. La parte pública de esta clave se almacena en la aplicación, y gracias a ella, se comprueba que la respuesta (permitiendo el acceso a la aplicación, o negándolo), ha sido realmente generado por el servicio de Google.

Burlando el sistema de licencias

Pero no ha pasado mucho tiempo hasta que han surgido los primeros problemas, y es que hace algunos meses se consiguio romper esta librería.

Y lo pongo en cursiva porque no se hasta que punto se puede considerar una vulnerabilidad, ya que no se explota ningún fallo, si no que simplemente se aprovecha lo fácil que es modificar código compilado en Java.

Java es un lenguaje que no compila a código máquina directamente, sino que genera un bytecode (código intermedio), que después se interpreta con la ayuda de una máquina virtual (Dalvik en el caso de Android).

El bytecode de Java es muy fácil de leer e incluso existen herramientas que lo desensamblan, dando como resultado un código muy parecido al original.

De esta manera, se puede coger una aplicación cualquiera protegida por esta librería, desensamblarla, desprotegerla y volverla a compilar.

Hasta aquí todo bien... podría parecer que es una tarea ardua y tediosa, pero nada más lejano de la realidad. A grandes rasgos basta con editar un simple salto (en un switch) en el fichero LicenseValidator para poder flanquear toda la protección que este sistema tenía que proporcionarnos.

¿Y como se arregla esto?

Bien, los ávidos lectores que hayan llegado hasta aquí se pueden preguntar si hay alguna solución al problema.

Pues Google nos ofrece una solución en un artículo que escribieron en su blog para desarrolladores. Recomiendan que se usen aplicaciones de ofuscación de código antes de distribuir la aplicación. Como ejemplo de esto ponen ProGuard, una de las mejores opciones que existen en Java.

Gracias a esta aplicación podremos hacer más difícil desemsamblar el código, ya que se eliminan todos los símbolos de depuración, se ofuscan todos los nombres y se quita todo el código que no es usado en el binario final.

En resumidas cuentas no solo nos ayuda a protegernos un poco más, si no que adelgaza el ejecutable y mejora su rendimiento, por lo que es recomendable usarlo más allá de la seguridad extra que pueda proveer.

Aparte de esto poco más podemos hacer. El uso de la librería en nuestra aplicación la hacemos nosotros, por lo que hay que evitar en la medida de lo posible seguir los ejemplos que proporciona Google a rajatabla, ya que generarán el mismo bytecode y será muy sencillo de parchear, por mucho que después ofusquemos el código.

Hola Mundo

+++++ +++++
[
    > +++++ ++
    > +++++ +++++
    > +++
    > +
    <<<< -
]
> ++ .
> + .
+++++ ++ .
.
+++ .
> ++ .
<< +++++ +++++ +++++ .
> .
+++ .
----- - .
----- --- .
> + .
> .

¡Y con este post queda inaugurado este blog! :)