Running GUI applications with Docker in OSX

A quick guide on how to run docker containers requiring a GUI with Mac and XQuartz. First, you’ll need to download and install XQuartz. Run it.
Now, start socat to expose local xquartz socket on a TCP port:

$ socat TCP-LISTEN:6000,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\"

Pass the display to container :

docker run -e DISPLAY=192.168.99.1:0 pygame xclock

I’m assuming that 192.168.99.1 is your vboxnet IP address and that «pygame» is the name of the docker image that contains your GUI application (in this case, my container’s name is pygame and the GUI is xclock)

For security purposes, you can use socat option range=/32 to filter the IP address (allowing only your primary IP to connect). Check also your XQuartz Preferences / Security tab:

Magic!

You can also launch a bash shell first and from there, run your GUI apps.

Sources:
[1] https://github.com/moby/moby/issues/8710#issuecomment-71113263
[2] http://fabiorehm.com/blog/2014/09/11/running-gui-apps-with-docker/
[3] https://github.com/CustardCat/pygame-docker

Cómo hacer un backup de tus mensajes de Telegram

Supongamos que quieres hacer un backup de los mensajes de un grupo (canal, supergrupo, conversaciones privadas, usuarios, whatever…) de Telegram.  Puede haber distintas razones para ello: simple copia de seguridad para estar tranquilo, porque vas a irte de un grupo, porque van a cerrar el mismo… o, como en mi caso, con fines estadísticos.

Hasta donde yo sé, Telegram no ofrece herramientas directas para esta labor, pero al usar un protocolo abierto y bien documentado, hay gente que se ha pegado el curro de implementar aplicaciones cliente desde cero. Una de esas aplicaciones es tg, escrita en C, software libre y ejecutable desde la línea de comandos. tg es «simplemente» un cliente de Telegram, pero ofrece -entre muchas otras funcionalidades interesantes- la opción de ser ejecutado en modo servidor. De esta forma, mediante scripting, nos será posible obtener toda la información que tengamos almacenada en esta plataforma de mensajería instantánea. Pero no adelantemos acontecimientos 🙂 Lo primero será compilar esta bestia, cosa nada fácil (al menos en OSX, donde estoy ahora mismo).

Descargamos tg y seguimos los pasos de compilación e instalación. En resumen:

git clone --recursive https://github.com/vysheng/tg.git
cd tg

En OSX necesitarás instalar dependencias usando brew como sistema de gestor de paquetes:
brew install libconfig readline lua python libevent jansson
Verás multitud de warnings relacionados con posibles conflictos de versiones (sqlite, readline, SSL…). Brew nos avisa de que OSX ya viene con algunas de esas librerías instaladas y que si queremos usar o compilar las de brew tendremos que cambiar las variables de entorno (PATH, LDFLAGS , CFLAGS, PKG_CONFIG_PATH). Bueno, por ahora haremos caso omiso a esos warnings. Y pasamos al siguiente paso:

./configure

Idealmente te debería mostrar un mensaje de que todo va bien.

Y llegamos al make, donde seguramente obtengas un error indicando algo similar a:

lua-tg.c:664:27: error: unused function 'get_peer' [-Werror,-Wunused-function]

Un error en la línea get_peer. Si es el caso, tendrás que aplicar este parche, así:

patch < lua.patch
Patching file lua-tg.c

y volver a ejecutar el make. Si todo va bien, obtendrás un mensaje como el siguiente y de premio, el ejecutable telegram-cli en la carpeta bin.

La primera vez que ejecutes tg tendrás que asociarlo con tu número de teléfono. No olvides indicar el prefijo +34 si estás en España. Te llegará un PIN de verificación al teléfono (a través de un mensaje Telegram). Es el PIN que deberás indicar en la línea CALL correspondiente.
u026627:bin juanan$ ./telegram-cli
Telegram-cli version 1.4.1, Copyright (C) 2013-2015 Vitaly Valtman
Telegram-cli comes with ABSOLUTELY NO WARRANTY; for details type `show_license'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show_license' for details.
Telegram-cli uses libtgl version 2.1.0
Telegram-cli includes software developed by the OpenSSL Project
for use in the OpenSSL Toolkit. (http://www.openssl.org/)
I: config dir=[/Users/juanan/.telegram-cli]
[/Users/juanan/.telegram-cli] created
[/Users/juanan/.telegram-cli/downloads] created
phone number: +34XXXXXXXXX
code ('CALL' for phone code): XXXXX
User Juanan Pereira updated flags
User Juanan Pereira online (was online [2017/03/20 14:15:45])

Ahora dispondrás de multitud de comandos (teclea help para ver la lista completa). Puedes probar que todo ha ido bien tecleando comandos como get_self, para obtener información sobre tu cuenta en Telegram, contact_list para ver un listado con el nombre de tus contactos o channel_list para ver el nombre de los canales y grupos a los que estás suscrito.

Es interesante remarcar que tg dispone de autocompletamiento en la línea de comandos (soporte readline), por lo que basta con teclear las primeras letras del comando y pulsar TAB para que rellene el resto. Para salir, teclear quit.

Para poder cumplir con el objetivo marcado al comienzo de este post (backup de los mensajes de un grupo) necesitaremos instalar un script que maneje tg de forma automática. Se trata de telegram-history-dump, escrito en Ruby:

git clone https://github.com/tvdstaaij/telegram-history-dump

Debemos asegurar que disponemos de una versión reciente de Ruby (>= 2.0).

ruby --version
ruby 2.0.0p648 (2015-12-16 revision 53162) [universal.x86_64-darwin16]

Ahora podemos decidir hacer backup de todo o sólo de algunos grupos en concreto. Yo sólo necesito backup de un super-grupo, así que edito el fichero de configuración del script config.yaml e indico en la sección [backup_supergroups] que quiero sólo el grupo "MI_GRUPO". En el resto de secciones, indico null.

Para finalizar, lanzamos tg en modo servidor:

./telegram-cli --json -P 9009

(escuchando en el puerto 9009 e intercambiando mensajes en formato JSON)

y ¡por fin! lanzamos el script de backup:

u026627:telegram-history-dump juanan$ ruby telegram-history-dump.rb
I, [2017-03-20T14:27:23.381792 #24590]  INFO -- : Attaching to telegram-cli control socket at localhost:9009
I, [2017-03-20T14:27:23.849295 #24590]  INFO -- : Skipping XXX dialogs: .....
I, [2017-03-20T14:27:23.849485 #24590]  INFO -- : Backing up 1 dialogs: "MI_GRUPO"
I, [2017-03-20T14:27:23.849783 #24590]  INFO -- : Dumping "MI_GRUPO" (range 1-100)
I, [2017-03-20T14:27:24.854833 #24590]  INFO -- : Dumping "MI_GRUPO" (range 101-200)
I, [2017-03-20T14:27:25.860089 #24590]  INFO -- : Dumping "MI_GRUPO" (range 201-300)
I, [2017-03-20T14:27:26.864448 #24590]  INFO -- : Dumping "MI_GRUPO" (range 301-400)
I, [2017-03-20T14:27:27.869046 #24590]  INFO -- : Dumping "MI_GRUPO" (range 401-500)
I, [2017-03-20T14:27:28.872592 #24590]  INFO -- : Dumping "MI_GRUPO" (range 501-600)
I, [2017-03-20T14:27:28.977374 #24590]  INFO -- : Finished

Tras unos segundos (veremos el progreso en la terminal donde tengamos lanzado telegram-cli) obtendremos el resultado en la carpeta output/ . Si disponemos del comando jq (si no, lo instalamos con brew install jq) podremos visualizar el JSON resultante cómodamente así:


cat output/json/MI_GRUPO.jsonl | jq

Espero que os haya sido de interés 🙂

 

Compilando phantomjs para ARM

Solución: Crear un fichero de SWAP https://www.cyberciti.biz/faq/linux-add-a-swap-file-howto/

y seguir compilando siguiendo la guía de la propia web de Phantomjs.

Done! Puedes descargar el binario desde este repositorio GitHub.

SSH-Vault: Cifrar y descifrar un fichero usando la clave ssh

Suelo pedir a mis alumnos que generen un par de claves SSH para darles de alta en alguno de los servidores que usamos en la asignatura (añadiendo la parte pública en el fichero de claves autorizadas, authorized_keys). Lo siguiente suele ser crearles una base de datos y un usuario con acceso a la misma. Aquí, el usuario necesita una contraseña. Para pasarles esta contraseña y otros datos privados, solía pedirles a su vez que me enviaran su clave pública GPG. Realmente, este último paso no es necesario… si disponemos ya de una clave pública SSH podemos usarla para cifrar y descifrar ficheros, muy fácilmente. Una de las formas más sencillas es mediante una aplicación de la línea de comandos, ssh-vault.com.

Para cifrar, usaremos el siguiente comando:

echo -n "mensaje a cifrar" | ./ssh-vault -k /ruta/a/clave/publica/id_rsa.pub create vault

Para descifrar, el receptor usará este otro comando:

./ssh-vault -k /ruta/a/tu/fichero/.ssh/id_rsa view vault

También podríamos haber evitado el uso de una aplicación extra, usando los comando ssh-keygen y openssl que seguramente ya tengamos (la «pega» es que un usuario Windows no las tendrá…):

Convertimos la clave pública ssh a formato PEM:

ssh-keygen -f ~/.ssh/id_rsa.pub -e -m PKCS8 > id_rsa.pem.pub

A continuación, ciframos el mensaje:

openssl rsautl -encrypt -pubin -inkey id_rsa.pem.pub -ssl -in myMessage.txt -out myEncryptedMessage.txt

El receptor usará también openssl para descifrar:

openssl rsautl -decrypt -inkey ~/.ssh/id_rsa -in myEncryptedMessage.txt -out myDecryptedMessage.txt

Fuente, cómo no, un hilo de discusión en SuperUser, una de las webs de la red StackExchange, la misma que alberga a StackOverflow.com

ngrok, o cómo resolver problemas a distancia

Llevaba unos cuantos días intentando resolver un problema de configuración de Apache a otra persona, por email. Me enviaba detalles del problema, pantallazos en algún caso y yo le respondía con posibles soluciones, comandos que debería ejecutar y ficheros de configuración que debería editar. Se trataba de una máquina local, detrás de un NAT. Tras muchas idas y venidas, no conseguíamos resolver y pensando en cómo solucionarlo, me encontré con una herramienta que me ha permitido hacerlo en 2 minutos, ngrok 🙂 Permite exponer puertos tras el NAT de forma muy sencilla, de tal forma que si expone por ejemplo el puerto 22, yo pueda conectarme de forma remota a administrar su máquina. Lógicamente debe haber confianza entre ambas partes, para evitar sustos de seguridad.

Para ello, la persona con el problema de configuración ha tenido que realizar los siguientes pasos:
Instalar openssh (si no lo tiene ya instalado):
$ sudo apt-get update
$ sudo apt-get upgrade
$ sudo apt-get install openssh-server

Poner en marcha openssh:

$ sudo service ssh start

Instalar ngrok (la aplicación que expone puertos tras el NAT)

Tras instalar, debe darse de alta: https://ngrok.com/signup
Una vez realizado ese paso,  ngrok le devolverá el comando a ejecutar para identificarse en ngrok. Algo como:
./ngrok authtoken XXXXXXX

Abrir el puerto 22 (ssh) al exterior: (magia!)

$ ./ngrok tcp 22
(Este comando te dará como resultado una dirección ngrok, que es la que tiene que enviar a la persona que le ayuda. Algo como:  tcp://0.tcp.ngrok.io:13011 )
La persona que le ayuda, en este caso yo 🙂  podrá conectarse así:
$ ssh -l usuario 0.tcp.ngrok.io -p13011

Lógicamente, la persona con el problema antes debe haberle enviado al ayudante un nombre de usuario y contraseña para conectar por ssh.

Una vez conectado, el ayudante puede abrir otras sesiones para tunelizar más puertos. Por ejemplo:

$ ssh -l usuario 0.tcp.ngrok.io -p13011 -L 8080:localhost:80

Ese comando permite tunelizar el puerto 80 de la máquina remota para dejarlo accesible a través del puerto 8080 de la máquina local. Es decir, si el ayudante en su navegador teclea ahora: http://localhost:8080 en realidad se estará conectando a través del túnel ssh al puerto 80 de la máquina remota (tras el NAT). Muy, muy interesante para permitir la administración remota de equipos. Lo dicho, en dos minutos he podido resolver así un problema que se estaba estirando ya unos cuantos días por la incomodidad de analizar el problema vía email…