Cuando se está viendo cometer un genocidio se dice y ya

Hoy es el último día del mes de noviembre y mi «disciplina» me obliga a escribir algo antes de que termine el mes (va a estar muuuuuuy al límite) y a la hora de ponerme a escribir tenía dos opciones:

  • Contaros cómo funciona la blockchain de bitcoin, que es con lo que ahora mismo estoy más entretenido
  • Dar una charla intrascendente sobre liderazgo, emprendimiento o estoicismo
  • Hablar de lo que me está indignando ahora mismo…

Y voy a optar por la tercer opción… Y no es una indignación política, como otras veces, es una indignación como ser humano, como habitante del planeta que se horrorizó de la existencia del holocausto y que no cree que, generalmente, la gente tenga que ser cruel. Pero si se está cometiendo un genocidio se dice y ya.

Me pueden acusar de antisionista (si quieren), de antisemita (los lerdos que no saben distinguir) o de simpatizante de hamás (si eso les mola, pues adelante), pero las cifras no engañan. Miles de muertos, la inmensa mayoría civiles y la mitad de ellos niños, masacrados como venganza por un acto abyecto de terrorismo. Tengo judíos en las redes que no hacen más que hacerse pasar por víctimas y justificar que una vida Israelí equivale a varias cientos de vidas palestinas (con toda su pachorra) y no deseas más que baje otra vez Jesús a machacar a los filisteos en plan peli de acción…

¿Estoy justificando lo que hizo Hamás? No, nunca, de ninguna manera… El terrorismo es violencia y yo soy contrario a toda la violencia, venga del IRA, de ETA o de Trump… Lo que hay que entender es que este terrorismo es una consecuencia y no la causa de los desmanes Israelíes. Veamos un poco de historia:

mapa cronologico

En 1947 Palestina era un país como cualquier otro, con su territorio, su gobierno, sus buenos y malos, sus leyes, su gobierno, sus jueces y… sobre todo, su territorio. En ese año los sionistas decidieron tomar al asalto (o haciéndose los tontos, que para el caso) su tierra prometida… Y las potencias aliadas, bueno, quisieron compensar el holocausto de alguna manera. Una manada de inmigrantes de todas partes de Europa se asentaron sin pedir permiso (ni perdón) en tierras que no eran suyas y decidieron, por su cuenta, pasar de la ONU y de todo formando su propio estado. Los que antes eran propietarios del territorio pasaron a ser solo parte de un país conquistado. A los que vivían ahí desde hacía generaciones se les negó todo derecho fundamental y durante años fueron oprimidos por la nueva fuerza de ocupación cuyo único objetivo era echar a los impuros de su estado religioso (como Irán, pero con otra religión)… Y en estas llegamos a los planes actuales. A estas alturas, con la mitad de la franja de Gaza destruida, la población diezmada y desplazada, sin electriidad, agua ni forma de recibir ayuda lo único que tiene interés para el estado de Israel es repoblar Gaza con asentamientos Judíos… Lo que nos venden como una guerra no es más que una conquista más, un Putin anexionándose Ukrania sin que nadie diga ni mu…

No quiero hacer más referencia a las posturas de unos y otros en la política nacional porque la mayor parte me producen una verguenza profunda pero, ya que tenía que escribir algo, te lo vuelvo a decir: Cuando se está viendo cometer un genocidio, se dice y ya…

AMAZON SES y cómo enviar correos desde un servidor ubuntu

Enviar correo desde una máquina virtual en Amazon siempre ha sido un castigo. Las limitaciones al puerto 25 y a los controles de tráfico de Amazon hacían poco recomendable poner un servidor de correo «normal» en la infraestructura. Sin embargo – y pagando, claro está – Amazon ha puesto a disposición de todo el mundo un servicio para poder enviar correos sin demasiada complicación (aunque, como veremos, también tiene sus limitaciones).

Lo primero es lo primero, si quieres mandar correos usando Amazon SES. La información general la puedes ver aquí: https://aws.amazon.com/es/ses/ y create una identidad verificada (tendrás que cambiar cosas en el dns para que puedas enviar correo desde cuentas de tu dominio. Lo siguiente será crear una configuración de SMTP para tu cuenta, eso te dará un servidor, usuario y contraseña que usar para mandar correos (y los puertos correspondientes)… Anotalos muy bien que será lo que vamos a utilizar.

Al principio tendrás unas limitaciones muy importantes (para probar no nos afectan demasiado) y tendrás que crear direcciones de correo validada, hazlo y prueba que puedes enviar correos a esas cuentas antes de continuar. Los pasos para poder enviar correo desde un servidor ubuntu serían los siguientes:

  1. Instala postfix
sudo apt install -y postfix libsasl2-modules
  1. Añade estas líneas a /etc/postfix/sasl_passwd
smtp_tls_note_starttls_offer = yes 
smtp_tls_security_level = encrypt 
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd 
smtp_sasl_security_options = noanonymous 
relayhost = [email-smtp.xx-xxxx-xx.amazonaws.com]:587 
smtp_sasl_auth_enable = yes 
smtp_use_tls = yes 
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt 
mydestination = 
  1. En /etc/postfix/sasl_passwd
[email-smtp.xx-xxxx-x.amazonaws.com]:587 USUARIO:PASSWORD
  1. Lanza las modificaciones
sudo newaliases 
sudo postmap hash:/etc/postfix/sasl_passwd 
sudo systemctl restart postfix

Y ya estaría, ya puedes enviar correos desde cuentas de tu dominio con sendmail. Si ves algún problema siempre puedes consultar el log en /var/log/mail.log

Si todo va bien lo siguiente es pedir a Amazon que, por favor, os pongan en producción el sistema para poder enviar correos a todo el mundo. Y ya si eso, en otro post, os cuento como configurar una imagen docker para que lo use…

Hacer un bot de telegram sin usar ninguna librería de telegram

Entiendo que conoces la aplicación telegram, lleva con nosotros mucho tiempo y, aunque en nuestro país es mucho más usada whatsapp, telegram tiene también sus adeptos, sobre todo para canales de distribución o para uso secundario con aquellos que ya usan esta herramienta.

Una de las características más importantes de esta plataforma es la separación entre usuarios y bots, los usuarios tienen que tener un número de teléfono registrado y no es tan sencillo hacerse con una cuenta adicional si no tienes otro teléfono, la plataforma distingue perfectamente entre personas y bots, que serían los programas a los que solo se permite interacturar con personas que hayan hablado con ellos antes o con canales de distribución a los que se hayan añadido como administradores (antes podían añadirse como miembros, pero esa posibilidad ya no existe). El caso es que llevo un tiempo desarrollando bots para esta plataforma, usando diversas librerías y después de tantear todos los límites de telegram y de las librerías me he visto obligado a ir directo al api de telegram para bots… Y resulta que no solo es sencillo, sino muy sencillo iniciarse en la creación de bots sin ninguna librería adicional… En este caso vamos a crear un bot de cero y sin librerías de por medio.

Pero, como decía Jack el destripador: vayamos por partes…

Lo primero es crear un bot, telegram pone a nuestra disposición el bot llamado botfather que nos permite crear bots asociados a nuestra cuenta (un máximo de 20 por si os sentís tentados de crear armadas de bots) y se crean simplemente con el comando /newbot y responder unas pocas preguntas… Como podemos ver en la imagen:

Lo importante, y fundamental, es el token que nos genera botfather, esto será todo lo que necesitamos para acceder al api, que como bien nos indican está en https://core.telegram.org/bots/api

Lo segundo será decidir en qué lenguaje y para qué plataforma vamos a crear nuestro bot, en nuestro caso y para simplificar las cosas vamos a hacerlo en python que puede correr en cualquier sitio (linux, mac, windows o incluso serverless), en mi caso vamos a crear un bot que, cuando se lo pedimos, nos genere una nueva contraseña (luego ya veremos si queremos mejorarlo). Por cierto, todo el código que generemos aquí estará en el repositorio https://github.com/yoprogramo/nomorepassbot para que podáis usarlo y modificarlo a voluntad.

Hemos dicho que no tendría dependencias de ninguna librería telegram, pero no hemos dicho que no la tuviese de alguna otra, así que es momento de decidir si queremos usar alguna librería http, en mi caso, por simplicidad he elegido la librería httpx, como tampoco quiero ir instalando cosas de más voy a utilizar pipenv para crear mi entorno de trabajo (vosotros podéis hacerlo como queráis)

La lógica del programa será sencilla, simplemente preguntaremos periódicamente a telegram si tenemos updates, y si los tenemos, miraremos a ver si alguna petición contiene la cadena «password» y si la contiene devolveremos una nueva contraseña generada por nosotros en ese momento. Para recuperar los updates haremos un bucle infinito en donde llamaremos a la función getUpdates y si recibimos elementos los recorreremos uno a uno para tratarlos.

La función para generar una contraseña aleatoria será esta:

def generatePassword(num=10):
    # Generamos una contraseña aleatoria de num caracteres
    letras = string.ascii_letters + string.digits
    password = ''.join(random.choice(letras) for i in range(num))
    return password

Lo primero que tenemos que hacer es dar un valor a nuestro token y establecer la url del api de telegram:

token = 'TOKEN'
url_base = f'https://api.telegram.org/bot{token}/'

Y la función que recupera las actualizaciones será, por tanto esta:

r = httpx.get(url_base + 'getUpdates')
    updates = r.json()['result']

La función para enviar un mensaje a un usuario (o a un chat) se llama sendMessage y recibe como parámetros (entre otros) chat_id y text, así que poniendo todo junto nos quedaría esta función:

while True:
    r = httpx.get(url_base + 'getUpdates')
    updates = r.json()['result']
    for update in updates:
        if 'message' in update:
            message = update['message']
            if 'text' in message:
                text = message['text']
                if 'from' in update['message']:
                    user = update['message']['from']
                    if 'password' in text:
                        respuesta = 'La contraseña es ' + generatePassword(10)
                        r = httpx.post(url_base + 'sendMessage', data={'chat_id': user['id'], 'text': respuesta})
                else:
                    continue 
    time.sleep(1) 

Si ejecutamos esto (y tenemos el token que nos ha dado godfather) ya podremos pedir la contraseña y recibiremos respuesta (al hablar con nuestro bot, claro):

Claro que si dejamos el código así el bot se empeñará en darnos contraseñas una detrás de otra sin parar, y es que telegram no sabe si hemos tratado o no el update que nos ha enviado, para ello hay que usar el parámetro offset para indicar cual será la siguiente actualización a tratar y cambiando el código un poco nos quedaría:

offset = 0
while True:
    r = httpx.get(url_base + 'getUpdates', params={'offset': offset+1})
    updates = r.json()['result']
    for update in updates:
        offset = update['update_id']
        if 'message' in update:
            message = update['message']
            if 'text' in message:
                text = message['text']
                if 'from' in update['message']:
                    user = update['message']['from']
                    if 'password' in text:
                        respuesta = 'La contraseña es ' + generatePassword(10)
                        r = httpx.post(url_base + 'sendMessage', data={'chat_id': user['id'], 'text': respuesta})
                else:
                    continue
    time.sleep(1)

Obviamente nos falta tratar las respuestas incorrectas y los timeouts y demás (y alguna respuesta adicional que nos puede dar telegram si hacemos demasiadas peticiones), pero eso lo dejo para que lo mejoréis en el repositorio https://github.com/yoprogramo/nomorepassbot

El caso Rubiales

Si, se supone que este es un blog de tecnología y no de política y menos de deporte, pero como en agosto hemos estado un poco amodorrados lo más interesante que tengo para hablar es esto… Así que dejaremos aquí mi opinión y ya.

Empecemos por lo más básico: dar un beso no consentido es delito. Lo es en España y lo es en mucho más países donde se considera una agresión sexual, aunque leve. Lo cierto es que muchas veces se trivializa con el tema, o se le quita importancia por herencias culturales que nos dicen que las mujeres están para eso.

Lo que algunos no se explican es cómo la carrera de alguien que gana casi 700.000 Euros al año se puede ir al garete por comportamientos de gañán redomado. Pero no es una cuestión de feminismo o de legalidad, es una cuestión de principios.

A fecha de hoy todavía no se conoce cual será el destino de Rubiales, atrincherado en su cargo, rodeado por su familia y defendido por la recua de desinformadores de la extrema derecha. Lo que está claro, y lo dejó claro en sus declaraciones, es que él no va a dimitir. Lo más normal sería que esperase a que le destituyesen para cobrar las indemnizaciones correspondientes, y mientras, prepara el camino para las inevitables querellas que le van a caer. Lo que si se sabe es que una amplia mayoría de la población no le quiere ver representando a nuestro país en ningún sitio y que la FIFA ya le ha sancionado en ese aspecto. Por lo menos la polarización actual parece que aquí es un poco menos, pero seguimos a la espera de qué harán las «fuerzas vivas» y si dejarán caer a este golfo o le mantendrán como representación de su poder.

La verdad es que este personaje tenía que haber sido cesado hace tiempo por sus corruptelas económicas, pero parece que tenía sostenes muy importantes en el mundo del futbol (no quiero decir quién) y ya se creía como el jefe indiscutible que podía hacer y deshacer a su antojo. Desconozco si es su forma de ser o es que ha tenido alguna alteración hormonal reciente, pero no veo muy normal que se agarre el paquete delante de millones de espectadores y junto a la Reina y la infanta para después plantarle un morreo televisado a una de las jugadoras (que por su orientación sexual tampoco es que lo vaya a apreciar mucho). Imaginaos esto en otros ámbitos fuera del deporte… Que tu jefe te pida un piquito y te lo plante por lo buenos que han sido los resultados trimestrales, que el representante de España en unas negociaciones se toque el paquete celebrando la firma del mismo y que, además, en la emoción del momento agarre a su secretaria y la plante un beso… Inaceptable, ¿no? Pues lo mismo con este sujeto. El futbol puede ser especial, pero no las actitudes de los que representan a un país o de los que tienen un puesto de poder sobre sus subordinados.

Lo que ya hizo este esperpento de persona después de que le pidiesen responsabilidades es de lo más despreciable que se puede imaginar. Presionar a la jugadora y a su familia para que saliesen a defenderle, sacar comunicados falsos haciendo creer que han sido redactados por la víctima, poner su huevos sobre la mesa en un discurso del «no dimito» digno del manual del machista ibérico y, sobre todo, negándose a reconocer que haya hecho algo mal son actos que no deberían quedar impunes.

Varias formas de hacer pruebas de stress a una url

Una vez que hemos programado algo, una web, un api o cualquier otra cosa que van a utilizar muchas personas a la vez nos entra la necesidad inmediata de, después de las pruebas unitarias, poder pasarle unas pruebas de stress para ver cuanta gente puede entrar a la vez antes de que el sistema reviente o, en el peor de los casos, ver si hay algún problema de programación que nos impide tener peticiones concurrentes con seguridad.

Servidor bajo asedio... Imagen generada por AI

Solo os voy a presentar los más sencillos, aunque luego hay herramientas mucho más completas que ya se deben usar en el momento de QA para comprobar si los requisitos del sistema se cumplen (máximo número de peticiones por minuto / curva de carga / evolución del tiempo de respuesta, etc.).. Pero vamos, que ahora mismo solo queremos ver si se puede llamar a nuestro api o web concurrentemente…

siege

Este es el comando más sencillo que he encontrado, pero a la vez es muy eficiente en lo que se puede hacer con él.

siege -c10 -r1 https://blaba.com

Tras un tiempo de ejecución (depende de los parámetros c: concurrencia y r: repeticiones) se recibirá una salida como esta:

{ "transactions": 140,
"availability": 100.00,
"elapsed_time": 3.12,
"data_transferred": 3.48,
"response_time": 0.22,
"transaction_rate": 44.87,
"throughput": 1.11,
"concurrency": 9.68,
"successful_transactions": 140,
"failed_transactions": 0,
"longest_transaction": 0.33,
"shortest_transaction": 0.04
}

Ahí ya podemos ver cual es el ratio de fallo para esa concurrencia y los tiempos máximos y mínimos para cada transacción. Guay…

Ahora bien, el problema viene de que solo podemos hacer peticiones GET (podemos poner las cabeceras que queramos, pero no hay manera de hacer una petición POST, por ejemplo). Así pues si tenemos que probar un API que tiene algo más que peticiones GET tendremos que usar otra cosa…

Sigue habiendo una infinidad de herramientas muy buenas para hacer estas cosas, como Jmeter y otras, pero para unas pruebas de carga básicas vamos a continuar con el camino «barato»

curl + bash

Si estamos en linux, tenemos suerte (el siege también es de linux, pero seguro que hay un port para tu sistema operativo). Apuntad esto:

Primero hay que instalar paralell que no está en la distribución por defecto:

sudo apt install parallel

Luego podremos escribir algo como esto:

seq 100 | parallel --max-args 0 --jobs 10 "./curl_to.sh"

Y en curl_to.sh poned el comando curl con el que vais a probar, por ejemplo este:

curl --location 'https://blabla.com/api/v1/micomando' --header 'Content-Type: application/json' --header 'Accept: application/json' --header 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIU...CvuTuF30k8XEFg_XL-gJyK-8rT4htC7HTHxbtDSGN8' --data '{ "userid": "418043893","message": "Hola payo…..", "uuid": "kk"}'

Este comando de antes lo que hace, básicamente, es lanzar una petición POST con un cuerpo JSON y una cabecera de autenticación (con un token JWT por ejemplo). Este código lo podemos sacar de postman, por ejemplo diciendole que queremos generar código para curl.

Si lanzamos el comando seq, lo que hace es generar una secuencia de números (en este caso de 1 a 100, y paralell lo que hace es lanzarnos de manera paralela (10 cada vez) el comando que hemos especificado… Con esto conseguiremos lanzar 100 veces 10 peticiones paralelas.

Obviamente no es perfecto, pero habremos podido simular una carga paralela sin tener que instalar nada en nuestro ordenador. Si eso lo combinamos con el comando time (os lo dejo como ejercicio) también podríamos sacar estadísticas de las ejecuciones.

En próximas entradas veremos como usar algunas herramientas muy potentes para pruebas de carga, pero por ahora, ya podéis empezar a estresar a vuestro servidor.