Ser empresario también es tener que tratar con malnacidos

Como se diría en twitter, acompañemé a conocer esta triste historia…

Luis Carballo Rua con nuestro portatil

Llevo 19 años siendo empresario y he contratado unas cuantas decenas de personas. Antes era más sencillo dar con alguien competente, pero ahora con tanto bootcam y con tanto FP con esteroides es más complicado saber si un trabajador sabe lo que dice que sabe o no. Antes tener un título significaba un mínimo, ahora tienes que bucear para encontrar si la persona en cuestión sabe lo que es el http o le han dicho que eso es magia de Angular. En fin, que se te pueden colar inútiles sin comerlo ni beberlo.

Uno de esos casos me pasó recientemente, una persona respondió a un anuncio de trabajo que pusimos en LinkedIn. La plaza que pedíamos de desarrollador front la terminamos ocupando con otra persona, pero me pareció interesante el cv que nos pasó, lleno de dibujos hechos por él mismo.

El caso es que en la siguiente plaza para full stack se volvió a presentar, decidimos entrevistarle y, quitando que hablaba muy deprisa, nos dijo que si a todo lo que le preguntamos, no parecía perdido en ningún área de los que preguntamos y su CV era molón, así que le hicimos una oferta a los dos días… Oferta que rechazó porque dijo que ya estaba trabajando en otra empresa que le llamó después de nosotros… En fin, cosas que pasan, a seguir entrevistando.

Esta vez el proceso se hizo un poco más largo y a eso de las dos semanas me contacta de nuevo diciendo que las condiciones de la nueva empresa no le interesan y que si le mantengo la oferta. Yo, que soy un hombre de palabra, le digo que le mantengo exactamente la misma oferta que le hice… Y, dicho y hecho, le preparamos el contrato y quedamos ya para que empiece a trabajar en remoto, básicamente, aunque esperábamos que al menos el primer día se quedase en la oficina para que le explicásemos las cosas.

Primer día: quedamos a las 9:30 porque yo tenía reuniones antes… Espero, se hacen las 10, las 11.., le mando un whatsapp, no me contesta, a las 12 ya le llamo por teléfono y me dice que está en Alcorcón, pero llevando su madre al médico, que luego se pasa por aquí (no me parece lo mejor para el primer día y, además, sin avisar), en fin, que a las 13 se pasa por la oficina, firma el contrato, le enseño a entrar en el portatil y en su cuenta de correo; y… Se va. ¡¡!! Que si, que es un trabajo remoto, pero leche, no solo llegas 4 horas tarde sino que ni siquiera te quedas a que te expliquemos nuestra forma de trabajar…

La primera semana de trabajo se perdió intentando que arrancase solo en ubuntu el portatil y que no usase windows (windows=kk), le compramos hasta una docking station para que pudiese enchufar sus dos monitores (y se lo tuvimos que mandar a casa, que él pasar por l oficina ya le daba pereza), la segunda semana ya empieza a hacer algo productivo pero sin hacer puto caso de lo que le decimos. Nos llena el código de librerías que luego tenemos que borrar y nos quita más tiempo del que ahorramos. En la cuarta semana le ponemos a hacer algo para despliegue inmediato (tampoco era muy complicado, pero dediqué yo más horas que él) y nos dice que se va a vivir a la costa que, total, es remoto y no nos vamos a enterar… Y el pavo se va de mudanza el mismo día que pasamos a producción grrrrr. Obviamente la cosa peta y tengo que arreglarlo yo solo.

Lo primero que hace nada más llegar a su destino es pedirme un anticipo (estábamos a día 7 de mes), cosa que me extraña pero que procedemos a hacer sin ningún problema. A partir de ese momento su rendimiento fue cero. La lista de problemas (en orden cronológico):

  • Que el proveedor de internet que tenía no le permitía usar el puerto del ssh y no podía subir nada al servidor
  • Que los que han venido a repararlo no tenían idea y ha terminado tirando el router por la ventana
  • Que me he quedado dormido (excusa para no aparecer por el daily) y el movil estaba descargado
  • Que se me acaban los datos del móvil
  • Que me van a poner la fibra (ese día desapareció tras el daily y apareció después de haber terminado la jornada diciendo que se había dejado el movil en casa mientras le instalaban la fibra)
  • Que me he cargado el móvil (caída fortuita al suelo, dice)
  • Que sigue sin fibra y tiene que hacer el daily desde un bar
  • Que el del bar ha abierto más tarde hoy y no he podido hacer el daily

Y mientras el trabajo que tenía asignado ahí pudriéndose y teniendo que hacerlo entre sus compañeros y yo…

Llegados a este punto decido que es suficiente y que, obviamente, no ha superado el periodo de prueba. Se lo comunico y le indico que empaquete el portatil, la mochila y la docking station y que alguien pasará a recogerla.

Y ahora salta la sorpresa en las gaunas… Esta persona decide que va a quedarse con el material de la empresa, material que vale más que lo que él ha generado para la empresa. Esto no solo está tipificado como una apropiación indebida sino que dado el valor de lo apropiado puede ponerle en un grave aprieto. Mi empresa, como no puede ser de otra manera, le ha pagado finiquito y liquidación (muchas tentaciones de quedarnos con ese dinero en compensación, pero mi abogado me recomendó pagarlo de todas formas) y este desalmado malnacido no ha dado señales de vida.

Ya es duro mantener y gestionar una empresa como para tener que lidiar con gentuza de esta calaña. No solo ha perjudicado a sus compañeros sino que te deja una mala leche que terminas pagando con el primero que pasa… En fin, solo espero que el karma haga su trabajo. Si alguien quiere contratar a un full-stack developer, que me pregunte a quien no contratar nunca.

JWT y Postman

O, mejor dicho, como probar tus APIs que usen JWT en postman.

Cuando estamos diseñando APIs es muy normal que, lo primero, las diseñemos sin pensar en el tema de la seguridad y, una vez que están funcionando, ya les añadimos los elementos de seguridad para que no puedan ser llamadas por cualquiera en producción.

Una forma, que yo he usado mucho, para fortificar las llamadas es hacerlo mediante un token que se ha obtenido con las credenciales de un usuario concreto, eso supone hacer una llamada previa al sistema del que se obtiene el token y, después, verificarlo en cada llamada. Esto, siendo un token arbitrario, supone sobrecargar el sistema de seguridad con llamadas de comprobación de token, además, tenemos que hacer caducar los tokens periódicamente ya que cualquier filtración del mismo da acceso a los recursos del usuario durante el tiempo que el token esté sin caducar.

Otra manera, ligeramente diferente, es utilizar JWT (JSON Web Tokens) que se diseñaron para poder transmitir credenciales y otra información entre sistemas de una manera más eficiente y segura. Lo único un poco «especial» es que tiene que haber un secreto compartido entre los sistemas que se comunican. Además, se usa ese secreto para firmar la comunicación, así que no es sencillo generar el token JWT de forma manual para las pruebas.

Si usas postman (que es lo que estoy usando yo últimamente) para hacer las pruebas, hay una manera de solventar el problema y que, básicamente, pasa por rellenar el campo pre-request script con este código:

// JWT generation script adapted from
// https://gist.github.com/corbanb/db03150abbe899285d6a86cc480f674d

var jwtSecret = pm.environment.get('jwt_secret') || ''

// Set headers for JWT
var header = {
	'typ': 'JWT',
	'alg': 'HS256'
};

// Prepare timestamp in seconds
var currentTimestamp = Math.floor(Date.now() / 1000)

var data = {
	'iss': pm.environment.get('jwt_iss') || '',
	'ist': pm.environment.get('jwt_ist') || '',
	'iat': currentTimestamp,
	'exp': currentTimestamp + 30, // expiry time is 30 seconds from time of creation
	'jti': 'jwt_nonce'
}


function base64url(source) {
    // Encode in classical base64
    encodedSource = CryptoJS.enc.Base64.stringify(source)
    
    // Remove padding equal characters
    encodedSource = encodedSource.replace(/=+$/, '')
    
    // Replace characters according to base64url specifications
    encodedSource = encodedSource.replace(/\+/g, '-')
    encodedSource = encodedSource.replace(/\//g, '_')
    
    return encodedSource
}

// encode header
var stringifiedHeader = CryptoJS.enc.Utf8.parse(JSON.stringify(header))
var encodedHeader = base64url(stringifiedHeader)

// encode data
var stringifiedData = CryptoJS.enc.Utf8.parse(JSON.stringify(data))
var encodedData = base64url(stringifiedData)

// build token
var token = `${encodedHeader}.${encodedData}`

// sign token
var signature = CryptoJS.HmacSHA256(token, jwtSecret)
signature = base64url(signature)
var signedToken = `${token}.${signature}`

pm.environment.set('jwt_signed', signedToken)
console.log('Signed and encoded JWT', signedToken)

En el mismo vemos que se usan estas variables que deberemos incluir en el entorno o en la petición:

  • jwt_secret : secreto compartido con el otro sistema
  • jwt_iss: issuer (como queramos identificar al emisor)

En cualquier caso también podríamos añadir el campo sub si es parte del payload que recibe nuestro API, o cualquier otro campo adicional que decidamos incluir, ya que el proceso de firma se realiza en ese momento y las fechas de expiración se actualizan justo antes de lanzar la petición al API por lo que no estarán expiradas en las pruebas.

Lo único que quedaría pendiente sería usar el token generado en la cabecera (o donde corresponda) ya que este código genera la variable {{jwt_signed}} esta la podemos usar donde queramos.

Sigo buscndo formas más sencillas para hacer las pruebas sin salir del Visual Studio Codel, si las encuentro las pondré por aquí.

Polarización

Me vais a perdonar porque abandone los artículos técnicos por un momento y os suelte una turra sociológico-política, pero es que últimamente entro mucho en twitter y me hierve la sangre más de lo que debiese, así que me voy a explicar un poco más calmado aquí que puedo poner todos los caracteres que quiera.

Imagen generada por la IA midjourney

Me podéis llamar progre (si, me gusta el progreso), izquierdista (si, creo que todos los humanos somos iguales y hay que hacer lo necesario para que la pobreza y la desigualdad no exista) e incluso me podéis tildar de rojo (no es mi color favorito, pero no tiene connotaciones negativas. En fin, que cada uno es como es y tiene opinión de casi todo (mejor si esta es informada). Tengo muchos y buenos amigos que son de derechas, de todos sus tipos, los hay muy cristianos, los hay liberales en lo económico y conservadores en lo demás, los hay que lo son porque es lo que escuchan en la tele (que tampoco han entrado a pensar mucho en ello, pero si lo dicen por algo será) y luego están los que son españoles ante todo y saben que los extranjeros son inferiores y han venido a quitar el trabajo a sus hijos (igual si se dedicasen a estudiar este riesgo no existiría…). Muchos de estos amigos son buenísimas personas y nada malvados, no dejaría de ser su amigo por nada del mundo.

El caso es que en el micro-cosmos de twitter y, según parece, en muchos medios de comunicación hay una tendencia increíble a evaluar los mensajes según su procedencia y catalogarlos como malos o buenos según si es de mi tendencia política o de otra. Hemos reducido la crítica a buscar las cosquillas a los que no son de nuestro bando, a pensar que los unos son unos demonios y los nuestros unos angelitos, y no, eso no es así. El espíritu crítico ha de guiar nuestros pensamientos siempre, tenemos que librarnos de estereotipos, de buscar segundas intenciones. Tenemos que leer los mensajes, analizarlos y decidir si estamos de acuerdo o no en conciencia, no como miembro de una tribu, sino como ser humano con nuestra conciencia y nuestras contradicciones.

No voy a poner ejemplos aquí, solo tenéis que leer las cuentas de zascas (que también se han polarizado en una de zascas a la izquierda y otra de zascas a la derecha) para ver que la coherencia no existe en ningún sitio y que los mensajes que mandamos al contrario no nos los solemos aplicar (ver la paja en ojo ajeno). Lo que si os pido, seais rojos, morados, azules o verdes es que intentéis mirar el mensaje primero y el emisor después y un último consejo (de los que vendo y para mi no tengo)… Recuerda que no siempre tienes la razón. Escribir el último tweet no te convierte en el ganador, solo en el que se ha cansado más tarde.

Como evitar perder la sesión cuando navego por un iframe

Recientemente he tenido un proyecto de página web que funcionaba perfectamente cuando se hacía directamente en el navegador, pero cuando intentaba meter el contenido en un iframe para integrarlo con otra parte de la web no conseguía que se mantuviese la sesión. Esto, además de un malestar insidioso, me produjo curiosidad, ya que hacía mucho que no utilizaba iframes y, parece, que la forma en que tratan estos ha cambiado un poco con las últimas versiones de los navegadores.

Aunque podría deciros la solución ya mismo, vamos a darle un poco de dramatismo y os voy a explicar porqué un iframe no se comporta exactamente igual que la navegación en el browser y como eso hace que puedas perder la sesión.

Imagen explicativa

¿Cual es la diferencia?

Un iframe no es más que un marco que se inserta dentro de una página web y cuyo contenido es cargado de una dirección distinta de internet, eso tiene la ventaja de que puedes enriquecer la página con contenido que no tienes que generar desde tu servidor, o que puedes reaprovechar cosas que ya tienes hechas en otros sistemas y el usuario podría no notar que esa parte del contenido proviene de otro sitio. Precisamente por este detalle (que los usuarios no son conscientes de donde viene ese contenido) se abren posibilidades de ataques Cross Site Request Forgery (CSRF), que significa que podrían recuperar una cookie de un dominio distinto desde una iframe, por ejemplo, y secuestrar la sesión original o cualquier credencial de usuario que viaje con las cookies.

Precisamente para evitar estos ataques en 2016 se estableció un atributo para las cookies (SameSite) que prevenía que se pudieran enviar cookies a dominios distintos de los que se estaba navegando (de lo que veíamos en la barra de navegación). Los posibles valores de estos atributos son:

  • None: las cookies se mandan a todos los dominios.
  • Strict: Las cookies solo se enviaran al dominio que coincide con el de la barra de direcciones
  • Lax: Las cookies se enviarán al contexto principal y con las navegaciones de primer nivel.

Antes de tener este atributo todas las cookies eran tratadas como si fuese None y los iframes podían recibir las cookies (entre ellas las de sesión), pero a partir de que los navegadores adoptaron el atributo, la cosa cambió y ahora si la cookie no declaraba el SameSite se consideraba que este era del tipo Lax y esto hace que la navegación dentro de un iframe que está en otro dominio no pase las cookies.

¿Cómo arreglarlo?

Básicamente lo único que tienes que hacer (esto ya depende mucho del framework que tengas) es declarar las cookies con este encabezado:

Set-Cookie: session=your_session; SameSite=None; Secure

Con esto declaramos que las cookies podrán ser retransmitidas, pero además que solo se transmitirán a dominios seguros (con https). Esta pequeña modificación hace que se pueda navegar ya dentro del iframe, pero, ¡cuidado! te añade un potencial problema de seguridad CSRF.

Cerrando el 2021

Dentro de dos meses hará 15 años que llevo manteniendo este blog, una eternidad en cuestión de tiempo tecnológico y una eternidad también en tiempo biológico. Generalmente se usa este último día del año para hacer un resumen de lo que se ha hecho y se ha dejado de hacer en el año saliente y dar la bienvenida a los nuevos planes y deseos para el año que entra… Bien, hoy no estoy de humor para ello (que eso no quita que no lo haga en algún momento), mi retrospectiva será más de estos 15 años de blog que de este año de pandemia continuada. Es más, se cumplen ya 20 desde que se publicó algo bajo este dominio… Y eso requiere un poco de historia.

Compré el dominio yoprogramo.com allá por 2001 poco después de haber contratado mi adsl con terra y con el ánimo de poner una web informativa sobre temas de programación. Yo, como muchos sabréis, me defino como programador, un programador con vocación empresarial y con muchas ganas de hacer cosas útiles por todo el mundo. De hecho, si sentís curiosidad, hay entradas de la web en Internet Archive (os muestro la primera de todas de Agosto de 2001):

En aquel momento firmaba como JaeSoft (Jose Antonio Espinosa) ya que lo que más deseaba era crear mi propia compañía de desarrollo de software, aunque por aquel año yo estaba en otra empresa (Sema Group – SlumbergerSema – Atos) haciendo cosas muy complicadas y muy interesantes para la época.

Intenté reunir personas interesadas en programar y en escribir, muy pocas se apuntaron y mi interés por mantener tantas secciones, incluyendo noticias, trucos y demás cosas que podrían servir para configurar un portal se resintió un tanto cuando perdí parte de los contenidos (aquí una imagen para que veáis como era la cosa en 2004 después de recuperar algunos):

A partir de ese año cambié mi rumbo laboral, abandoné la multinacional en la que había trabajado y me puse por mi cuenta. La web sufrió un hackeo en que, afortunadamente, no perdimos nada (pero publicamos el artículo) y la web pasó a estar patrocinada por la nueva empresa que acababa de fundar (Digimate Computer)… Incluso patrocinaba la web más loca que nunca he publicado, una que se llamaba «quiero mi wii» que me ayudo a conseguir una consola wii en un momento en el que había una escased tremenda de ellas. Fue tanta gente la que quería la wii que tuvimos una avalancha de visitas el poco tiempo que estuvo activa:

Hasta que un día de 2007 decidí cambiar de formato, abandonar el portal para el programador que, aparentemente, no usaban demasiados programadores y me daba muchísimo trabajo mantener y creé (utilizando un wordpress que había aparecido el año pasado) mi blog personal.

Y si hace 15 años que llevo escribiendo en este mi blog, puedo seguir escribiendo algunos más… Intentaré estirar lo más posible mi dedicación al mismo durante este año entrante y, finalmente, os deseo a todos que el año 2022 os sea propicio. Desear es gratis, pero es una buena cosa para variar…

Feliz 2022