
Últimamente y cada vez más, están apareciendo servicios en internet que son gratuitos y normalmente estos servicios al estar enfocados a nivel mundial requieren gran cantidad de recursos por lo que se ejecutan en eso que llaman "clowd computing".
Por supuesto el futuro de internet está ahí y con estas nuevas redes se pueden hacer cosas que antes eran imposibles.
Normalmente estos servicios son gratuitos hasta que realmente quieres hacer un uso real de ellos, que se basan en cuentas premium y demás, lo que puede llevar a una especie de separación de internet en dos, la internet premium y la internet base.
En principio puede parecer que no hay mucho problema con eso, pero sí que lo hay realmente y un ejemplo claro puede ser la separación de internet en dos redes más o menos independientes , la de los ricos y la de los pobres.
Pero la parte más perjudicada aquí es la libertad. La libertad del usuario a usar el software. En esta "futura" red lo que te están vendiendo es un servicio, no una licencia de uso ni un software, por lo tanto tú estás pagando por tener acceso a determinado servicio como puede ser una cuenta de correo.
Por lo tanto y escudándose en que el software realmente no se "ejecuta" en tú máquina, el software libre dejaría de tener sentido y aquí comenzaría la gran perdida para los usuarios en general y las grandes ganancias para las compañías que ofrezcan servicios.
"Siempre podremos desarrollar software libre", esta frase no es totalmente cierta, porque aunque tú puedas y tengas los conocimientos para desarrollar una aplicación libre no vas a tener la infraestructura necesaria ni vas a poderla desplegar en la "internet del futuro" si no eres una gran compañía con dinero para pagarlo.
Por lo tanto es necesario adelantarse a los acontecimientos y crear nuevas redes públicas donde todo el mundo pueda desarrollar y no esperar a que la mayoría de los servicios sean privados y tengamos que pagar un pastizal para usar las herramientas del futuro. Así pues necesitaremos hardware libre, redes y dispositivos móviles libres para poder al menos mantener el grado de libertad en el software que utilizamos y por ende en la información que sí es nuestra y debemos cuidar.
El dinero será un problema para muchos pero no será el problema principal, porque además de perder gran parte del control de nuestros datos (algo que ya estamos haciendo) perderemos la liberta de usar el software para lo que queramos, la libertad de estudiar el software para aprender, la libertad de modificar el software para adaptarlos a nuestras necesidades y la libertad de distribuirlo, puesto que en este modelo no existe software sino servicios.
Tim Orreilly estuvo hablando sobre esto en Málaga, en la Open Source World Conference, pero desde el otro punto de vista, justificando que en la futura red orientada a servicios no tenía sentido el software libre y lo que sí tenía sentido eran las apis libres de los servicios gratuitos.
Como podréis ver, realmente sí que tiene sentido el software libre, siempre y cuando prime la libertad ante "lo gratuito", porque realmente se perdería mucho si dejamos que internet caiga en manos del corporativismo y se convierta en algo totalmente diferente.
Esta es una opinión formada a partir de lo poco que se y de mis conocimientos sobre la tecnología, por supuesto mi visión no trata de conseguir más dinero o empresas o trabajo, sino de que la tecnología siga siendo libre y que todos, y cuando digo todos quiero decir todos, podamos acceder a ella, cosa que hoy, por lo menos en Andalucía es más o menos factible. Por supuesto el acceso debería ir acompañado de algo de formación, pero por lo menos el acceso debería estar garantizado.

Según mi planificación inicial debería haber llegado a este punto hace ya algún tiempo, pero entre unas cosas y otras pues llego ahora. De todas formas la parte más compleja, ya sea diseño y arquitectura del sistema, está al 80%, es una versión funcional y a partir de este punto voy a iterar hacia la perfección.
¿A dónde he llegado? Ya tengo un gestor de contraseñas basado en el sistema de cliente servidor funcional. Tengo un servidor que exporta una interfaz xmlrpc (gecod) y un cliente para terminal (gecoc) que basandose en esta interfaz te da la funcionalidad esperada.
La funcionalidad implementada es:
- registro de nuevos usuarios
- crear una nuevo contraseña
- borrar una contraseña
- ver una contraseña
- listar todas las contraseñas
Esta funcionalidad es más que suficiente para un gestor de contraseñas, teniendo en cuenta que la creación de contraseñas incluye la generación de contraseñas aleatorias y que también se hace uso de cifrado para mayor seguridad.
Sin embargo GECO está pensado para gestionar, además de contraseñas, ficheros de configuración, pero esto lo implementaré más tarde, aunque lo he tenido en cuenta a la hora de crear la base de datos.
Con respecto al cliente he creado un cliente interactivo con una serie de ordenes, con ayuda y demás cosas, se puede ver cómo lo he hecho aquí. Lo he hecho de tal manera que cada función definida es un nuevo comando y se utilizan las cadenas de documentación de python para mostrar la ayuda.
Usabilidad:
Al basarme en el modelo cliente servidor estoy metiendo un poco de complejidad a la forma de llegar hasta la información almacenada ya que es necesario recordar al menos dos contraseñas "seguras" para poder acceder al resto.
Al estar la información almacenada en un servidor externo, es necesario tener un usuario y contraseña en ese servidor para poder gestionar todas las contraseñas que se almacenen, por lo tanto tendremos que tener un usuario y contraseña para acceder desde las diferentes interfaces a un servidor geco.
Por otra parte como las contraseñas pueden almacenarse en un servidor que no controlemos es necesario cifrarlas con un algoritmo simétrico, para lo cual hace falta usar una clave maestra de cifrado de passwords (esta nunca llegará a ningún servidor).
Supongo que para servidores locales se puede evitar el paso de la autenticación y proteger la base de datos basandose en el sistema de ficheros, así actuaría como un gestor de contraseñas tradicional, pero en cuanto implemente la posibilidad de sincronizar diferentes servidores le dará mucha más potencia.
A partir del cliente para terminal se puede empezar a trabajar en diferentes clientes (web, gtk, qt, etc).
Algoritmos de cifrado
Como tengo pensado hacer un cliente web es necesario que las contraseñas se cifren con un algoritmo que tenga una implementación en javascript y en python, así pues me he basado en SlowAES para cifrar y descifrar y así tener asegurado que es posible descifrar y cifrar desde el navegador. Esta librería también incluye una implementación en ruby por lo que es posible crear un cliente basandose en ruby. Por supuesto también he tenido en cuenta que el metodo de cifrado puede ser variable por lo que intentaré añadir más sistemas de cifrado.
Nada más por hoy, yo voy a empezar a utilizarlo y a tener una contraseña aleatoria para cada servicio web.

Hoy en día todo el mundo confía en el correo electrónico, todos confiamos en que los correos que nos llegan vienen realemente de quien dice que viene. Para el que no lo sepa, el correo electrónico no va autenticado, un correo es igual que una carta, el remitente lo pone quien lo envía, y en ningún paso del proceso se verifica la identidad del mismo.
¿Cómo envíar un correo con la dirección que yo quiera?
Hacer esto en linux es extremadamente sencillo. Para el envío de correo se utiliza el protocolo SMTP. El correo se envía desde servidores SMTP, si escribes un correo desde gmail, por ejemplo, se utiliza para mandar el correo uno de los servidores smtp de google.
Por lo tanto si queremos envíar correo desde nuestro ordenador tenemos que instalar un servidor smtp, como por ejemplo postfix (en debian/ubuntu/etc apt-get install postfix).
Cuando lo ejecutamos tenemos en el puerto 25 de nuestra máquina el servicio corriendo:
$netstat -punta | grep -i LISTEN
tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN -
Con el servidor smtp hay muchas formas de envíar correos (telnet, mail, sendmail, cualquier cliente de correo, ...)
Voy a poner un ejemplo de script en python que envía un correo con una dirección de correo dada
#!/usr/bin/python # pymail.py <a href="mailto:from@mail.com">from@mail.com</a> "to@mail.com;to2@mail.com;..." "subject" "message" import sys import smtplib if len(sys.argv) < 5: print 'pymail.py <a href="mailto:from@mail.com">from@mail.com</a> "to@mail.com;to2@mail.com;..." "subject" "message"' sys.exit() fromm = sys.argv[1] to = sys.argv[2] subject = sys.argv[3] message = sys.argv[4] msg = ('From: %(fromm)s\r\nTo: %(to)s\r\nSubject: ' '%(subject)s\r\n%(message)s' % globals()) s=smtplib.SMTP("localhost") s.sendmail(fromm, to.split(';'), msg)
Yo por ejemplo me he envíado un correo desde google@google.com
python pymail.py "Google INK <google@google.com>" "Daniel García Moreno <danigm@gmail.com>" "Te voy a decir hola" "Hello world"
Y aquí está en mi correo.

Cómo evitar esto
Si has recibido algún correo mío alguna vez habrás visto que casi siempre lleva un adjunto signature.asc, pues bien, eso es la firma del mensaje. Existen mecanismos como GnuPG para poder verificar que el mensaje viene de quien dice venir, incluso se puede cifrar el mensaje para que sólo el destinatario pueda leerlo (los correos van en claro de servidor a servidor por la red). Cualquier cliente de correo que se precie es capaz de firmar con pgp/gpg, verificar las firmas y cifrar (yo uso evolution). Si la firma es válida podemos estar seguros de que el mensaje viene de quien dice que viene, incluso podemos asegurar que no ha sido alterado.
Para crear y manejar tus claves gpg puedes utilizar seahorse en gnome.
Mi clave pública es: FE6A3613

El proyecto sigue avanzando paso a paso. Hoy he implementado un frontend para el demonio de GECO (gecod) que implementa una interfaz XMLRPC con ssl.
Dado que vamos a mandar información sensible hacia el servidor es necesario que la conexión se haga a través de un canal seguro, por lo tanto he buscado por ahí la forma de tener un servidor xmlrpc en python sobre ssl y lo he encontrado.
A partir de ese código he creado el módulo python secure_xmlrpc. Y básandome en este, crear un servidor XMLRPC sobre ssl es tan fácil como declarar una clase y pasarle una instancia de esta al constructor de la clase EasyServer.
... import secure_xmlrpc as sxmlrpc ... class frontend: ... def auth(self, user, password): ... def start_server(): sxmlrpc.EasyServer(HOST, PORT, frontend()) ...
Por otra parte, en el lado del cliente, he empezado creando un módulo (utils) el cual ahora mismo tiene un generador de contraseñas "aleatorias" y una función que comprueba la seguridad de una contraseña de forma simple.
Para generar una contraseña aleatoria he usado los módulos random y string. Está parametrizado el conjunto de caracteres a utilizar y el tamaño de la contraseña generada. Con random.choice y una lista por comprensión genero la contraseña a partir del conjunto de caracteres seleccionado.
import random import string LOWER, UPPER, DIGITS, PUNCT = (string.lowercase, string.uppercase, string.digits, '.:;,!?{}[]<>=-_()+') def generate(size=11, lower=True, upper=True, digits=True, punctuation=False): chars = '' selection = [lower, upper, digits, punctuation] strings =(LOWER, UPPER, DIGITS, PUNCT) for opt, v in zip(selection, strings): if opt: chars += v return ''.join([random.choice(chars) for _ in xrange(size)])
Para comprobar la seguridad de las contraseñas he implementado una función que comprueba características básicas de las contraseñas y devuelve un valor entre 0 y 1.
Los test que he implementado son:
- contraseña en una lista de palabras
- la contraseña es una secuencia ordenada
- según el tamaño (<=4, <=6, <=8, >=14)
- la contraseña contiene algún caracter (minusculas, mayusculas, digitos, puntuación)
def strength(password): ''' return 0..1 ''' strength = -5 # bad passwords tests (-20 or -15) bad_passwords = ('', 'qwerty', 'asdf', 'zxcv', '123', '1234') if password in bad_passwords: return -20 ord_pass = [ord(i) for i in password] inverted_pass = ord_pass[:] inverted_pass.reverse() if is_sorted(ord_pass) or is_sorted(inverted_pass): return -15 # len tests (min -10, max 5) if len(password) <= 4: strength -= 10 elif len(password) <= 6: strength -= 8 elif len(password) <= 8: strength -= 5 elif len(password) >= 14: strength += 5 # chars tests (max +20) for chars_string in LOWER, UPPER, DIGITS, PUNCT: for j in chars_string: if j in password: strength += 5 break return ((strength + 20) / 40.0) def is_sorted(alist): ''' alist is a list of ints ''' first = alist[0] i = 1 while i < len(alist): if first != alist[i] - 1: return False first = alist[i] i += 1 return True
Con esto y un bizcocho, podremos generar contraseñas y verificar su seguridad con suma facilidad.

Ya he creado la primera versión de la base de datos, con sqlalchemy, para el demonio del gestor de contraseñas GECO.
La base de datos es necesaria para almacenar las contraseñas ya cifradas, así como los usuarios que están registrados en ese demonio.
En principio sólo tenía pensado crear tres tablas, la de los usuarios, la de las contraseñas y la de los ficheros de configuración, pero he añadido una cuarta (cookies).
Las tres primeras están más o menos justificadas dada la aplicación que me he propuesto desarrollar. Necesito guardar los usuarios registrados. Para cada usuario tendré que almacenar las contraseñas y ficheros de configuración que gestione con la aplicación.
La cuarta viene dada por la forma en la que estoy implementando el backend del demonio. La idea es que el frontend sea totalmente "independiente" del backend, sólo haga llamadas a una serie de funciones. He pensado que una buena (y simple) manera de hacer esto es mediante un sistema de cookies similar al que utilizan los navegadores, para así evitar que el frontend esté continuamente pasandole la contraseña del usuario (aunque sólo sea un hash de la contraseña real) al backend (aunque no haya transferencia por la red).
Por lo tanto con el sistema de cookies que he implementado, el frontend llamará a la función autenticar (que admitirá más de un método de autenticación, actualmente sólo está implementado por usuario y contraseña) y esta función devolverá una cookie. Para cada petición que quiera hacer el frontend al backend, en lugar de pasar usuario y contraseña, sólo tiene que pasar la cookie.

De momento hay poco código, pero el sistema va tomando forma, y estoy intentando mantenerlo lo más simple posible. Tengo que escribir un poco más de código y de documentación para poder recibir colaboraciones, dado que de momento la idea está en mi cabeza, por lo que no hay una forma sencilla de colaborar en el proyecto.
Estoy manteniendo tanto el repositorio en la forja de rediris como en mi propio servidor, y para ello estoy utilizando bzr-svn, con lo que con un "bzr push" hago un commit en la forja de rediris.

Hoy he hecho un dibujo de un pingüino navideño y de paso lo he grabado, le he puesto un poquito de música y lo he colgado en youtube.
Para grabarlo he usado gtk-recordmydesktop y luego con mencoder lo he transformado, escalado y le he puesto música de Rob Costlow.
Lo he realizado en Archlinux con mi dell xps1210 dibujando con inkscape y mi touchpad.
Aquí el vídeo:
Aquí el resultado:


Hace ya algún tiempo comencé a versionar todos mis proyectos con bazaar. La mayoría de los cosillas que hago son pequeños proyectos que no tienen mucha continuidad en el tiempo y no tiene sentido que se publiquen en forjas al estilo de launchpad. Así que ya que tengo mi servidor virtual subo las ramas a mi servidor a través de bzr+ssh. Con bazaar montar un repositorio es tan fácil como hacer un bzr push a otra máquina en la que tengas una cuenta ssh.
Por lo tanto en mi servidor tengo una carpeta "/home/danigm/branchs" dentro de la cual están todos mis proyectos. Cada proyecto es una carpeta que es un repositorio bazaar o una rama. Con bazaar es posible hacer branch o checkout desde una rama cualquiera.
Por otra parte hace poco descubrí web.py que es lo que andaba buscando hace ya algún tiempo. Una forma simple de desarrollar páginas web en python, sin mega-framework que complican el trabajo más de lo que lo facilitan.
Juntando estas dos cosillas ayer me puse a desarrollar un pequeño visor de repositorios bzr basandome en la estructura que yo tengo en mi servidor y el resultado puede verse en http://repo.danigm.net:8000/projects.
bzr-viewer tiene las siguientes funcionalidades:
- Visión de un listado de proyectos (carpetas bzr) (http://repo.danigm.net:8000/projects)
- Visión de los ficheros versionados en cada proyecto por revisión (http://repo.danigm.net:8000/list/bzr-viewer/5)
- Visión de logs de cada proyecto (http://repo.danigm.net:8000/log/bzr-viewer)
- Exportación de cada proyecto y revisión a tgz para descarga (http://repo.danigm.net:8000/tgz/bzr-viewer/5)
- Visión de diferencias entre dos versiones cualesquiera de un proyecto (http://repo.danigm.net:8000/diff/bzr-viewer/4/5)
- Visión/descarga de ficheros de un proyecto en cualquier revisión (http://repo.danigm.net:8000/view/bzr-viewer/index.py/1)
Puedes echar un vistazo en mi repositorio y te puedes bajar el código para ver un ejemplo de applicación simple con web.py.
Actualizado (vie ene 9 08:22:24 CET 2009)
Ya no tengo bzr-viewer para mi repositorio, sino que he modificado un poco loggerhead para que haga la misma función, pero de una manera mucho más completa.

En el esquema de la arquitectura de GECO aparece como una parte bastante importante en el demonio "gecod" SQLObject.
Un ORM simplifica el acceso a una base de datos por parte del programador convirtiendo toda sentencia sql a operaciones con objetos. Así por ejemplo añadir una fila a una tabla es tan fácil como crear un objeto.
Después de algún tiempo pensandolo he decidido que sería mejor opción utilizar SQLAlchemy, ¿por qué este cambio? Bueno, son varias razones las que me han llevado finalmente a explorar este nuevo ORM:
- Es más potente que SQLObject
- Ya conocía SQLObject, una oportunidad de conocer otro ORM
He estado mirando un poco la documentación de SQLAlchemy y voy a explicar de forma breve la manera más sencilla de utilizar este ORM en python.
Definición de una tabla/objeto
from sqlalchemy import * from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relation, backref, sessionmaker Base = declarative_base() metadata = Base.metadata class User(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(20)) fullname = Column(String(50)) def __init__(self, name, fullname): self.name = name self.fullname = fullname def __repr__(self): return "<User('%s','%s')>" % (self.name, self.fullname) db = create_engine('sqlite:///database.sqlite', echo=False) metadata.create_all(db)
Así de fácil se declara un simple objeto. Esto se refleja en una base de datos con una tabla, de nombre 'users', con las columnas id, name y fullname.
Con metadata.create_all(db) se crea la tabla en la base de datos (La base de datos puede ser sqlite, mysql, postgresql,...).
Creación de objetos
Session = sessionmaker(bind=db, autoflush=True) session = Session() u = User('dani', 'daniel garcia') session.save(u) session.commit()
De esta forma tan simple se pueden crear usuarios que se verán reflejados en la base de datos relacional como una nueva fila en la tabla de usuarios.
Es necesario crear un objeto de tipo session para interactuar con la base de datos.
Y para eliminar una entrada nada más simple que
session.delete(u) session.commit()
Consultas
session.query(User).filter(User.name == 'dani').all()
Se pueden hacer multitud de consultas con filter y además se pueden concatenar filters -> filter(User.name == 'dani').filter(User.fullname == 'daniel garcia')....
Relaciones
class Address(Base): __tablename__ = 'addresses' id = Column(Integer, primary_key=True) email_address = Column(String, nullable=False) user_id = Column(Integer, ForeignKey('users.id')) user = relation(User, backref=backref('addresses', order_by=id, cascade='all, delete-orphan', passive_deletes=False)) def __init__(self, email_address): self.email_address = email_address def __repr__(self): return "<Address('%s')>" % self.email_address
Si queremos declarar una tabla que esté relacionada con otra se utiliza ForeignKey. Además hay que definir una relación, y backref nos da la referencia en la tabla padre, es decir que la tabla padre tendrá este atributo. Con cascade y passive_deletes se consigue el borrado en cascada, cuando se borre un usuario se borraran todas los emails asociados a este.
u = session.query(User).filter_by(name='dani').one() print u.addresses u.addresses.append(Address('dani@danigm.net')) print u.addresses session.commit() session.query(User, Address).filter(User.id == Address.user_id).filter(Address.email_address == 'dani@danigm.net').first()
Con este ejemplo se ve como se pueden hacer consultas sobre la unión de varias tablas.

He añadido soporte para twitter en sweetgtk y arreglado una serie de bugs.
Ahora Se puede seguir twitter y/o sweetter al mismo tiempo y escribir comentarios en sweetter y/o twitter. He añadido unos checkbox y dependiendo de si tienes seleccionado sweetter o twitter o ambos se reciben los comentarios y se postea en la plataforma adecuada.
Aquí un screenshot de la nueva versión:

Además he arreglado el script install que era una guarrería y ahora se hacen las cosas de buena manera, llevando todo a /usr/share/sweetgtk y la configuración y la cache a $HOME/.sweetgtk de cada usuario, copiandose un skel si este directorio no existe.
Así pues todo aquel que intentó instalarse sweetgtk sin exito debe ejecutar el script ./uninstall de la versión que intentó instalar y borrar todo archivo que quede por ahí suelto, incluso $HOME/.sweetgtk, bajarse la nueva versión y ejecutar el nuevo script install como root que hará todo lo pertinente.
El script install debería funcionar en la mayoría de las distros GNU/linux y por tanto en el openmoko. Las dependencias y demás cosas están en el post anterior
Por otro lado lo he empaquetado para debian/ubuntu y aquí está el paquete:
sweetgtk_2.0_i386.deb
Gracias por vuestra atención y a disfrutar del microblogging.

Hacía ya tiempo que tenía pensado hacer una aplicación de escritorio para poder interactuar con sweetter, pero hasta hoy no me había puesto a hacer nada serio.
Consiste en una aplicación hecha en pygtk que tira del módulo que ya hice antes pysweetter (que se conecta a sweetter a través de xmlrpc de forma transparente).
El código se puede conseguir así:
bzr branch http://repo.danigm.net/sweetgtk
Está bajo el control de versiones bazaar
Aquí una captura de pantalla de la aplicación:

Y como es pygtk también funciona en el openmoko neo freerunner:

Todavía estoy desarrollandolo, estoy teniendo problemas con los threads porque me da "segmentation faults" de forma "aleatoria", tengo que arreglar eso :P
Edito (23/11/2008 21:40):
Creo que ya he solucionado el problema de los threads, y además he hecho algunos arreglos para que funcione también en windows.
Aquí un screenshot funcionando en windows:

Para que funciones en windows vista hay que instalar una serie de cosas:
- Instalar python 2.5: http://www.python.org/download/
- Instalar GTK-runtime: http://sourceforge.net/project/showfiles.php?group_id=98754
http://sourceforge.net/project/showfiles.php?group_id=98754&package_id=1... - Instalar pygtk: http://ftp.gnome.org/pub/GNOME/binaries/win32/pygtk/2.12/
- Instalar gobject: http://ftp.gnome.org/pub/GNOME/binaries/win32/pygobject/2.14/
- Instalar pycairo: http://ftp.gnome.org/pub/GNOME/binaries/win32/pycairo/1.4/
Y por cierto, para que funcione en linux también es necesario tener instalado todo lo anterior, pero normalmente en un escritorio gnome estará instalado, los paquetes para debian son:
python, python-gtk2, python-gobject, python-cairo, python-notify
Tengo pensado hacer un paquete un día de estos, mientras tanto se puede conseguir el código del repositorio o de aquí:
http://danigm.net/files/sweetgtk.tgz


