Subir a maven central una librería propia

Ahora que ya acabas de construir una librería interesante en Java, la has hecho pública (en github, por ejemplo) y quieres que todo el mundo la use… Queda una tarea pendiente, subirla a un repositorio maven para ponerla a disposición de los que utilicen este sistema (o gradle, que hoy en día ya son casi todos).

Vamos a verlo con un ejemplo que he subido esta mañana… Hay cosas que todavía no entiendo del todo, pero el resultado ha sido bueno, por lo que, al menos, podremos usar esta receta como guía para próximas veces.

El código que intento subir es una librería simple que tengo alojada en github con su pom.xml básico y que si te descargas el proyecto podrías compilar e instalar en tu maven con mvn install. La dirección es esta:

https://github.com/yoprogramo/nomorepass-java/

Ahora, para que todo el mundo pueda descargárselo como dependencia y no tenga que hacer el mvn install del proyecto, tenemos que subirlo a un repositorio público, podemos ver una guía en esta página: Guide to Public Maven Repositories. Tal como explican en la página, lo más sencillo para publicar en Maven Central es usar el repositorio Sonatype. Dicho y hecho… Lo intentamos por aquí.

Lo primero es crear una cuenta en el Jira de Sonatype aquí. Lo siguiente, y esto es un poco «tricky» es crear un ticket solicitando un nuevo id de grupo en esta dirección. No se puede pedir cualquier id de grupo (en mi caso quería pedir com.nomorepass) y generalmente se pedirá alguna prueba de que el dominio es tuyo. En mi caso este es el ticket que creé: https://issues.sonatype.org/browse/OSSRH-49426, para demostrar que el dominio era mío cambié el DNS e incluí una entrada TXT con el identificador del ticket:

Una vez autorizado (tarda un poco, es un proceso manual) hay que modificar nuestro código y prepararlo para la subida, pero, antes de eso, tenemos que generar nuestras claves gpg para poder firmar el código. eso se hace con este comando:

gpg --gen-key

Una vez generada podremos acceder a la lista de claves con el comando:

gpg --list-keys

Toma nota del id de la clave y recuerda la contraseña que usaste para generarla, porque tendrás que recordarla. Además, tendrás que publicarla en algún servidor de claves públicas para que pueda ser comprobada.

gpg --keyserver hkp://keys.gnupg.net --send-keys <el-id-de-la-clave>

Ahora empezamos a modificar el pom.xml para que cumpla con los requisitos para el repositorio Maven Central. En nuestro caso pusimos esto:

<groupId>com.nomorepass</groupId>
  <artifactId>nomorepass</artifactId>
  <version>1.0</version>
  <packaging>jar</packaging>

  <name>Nomorepass java library</name>
  <description>NoMorePass protocol 2 implemented on Java.</description>
  <url>https://nomorepass.com</url>

  <licenses>
    <license>
      <name>Apache License, Version 2.0</name>
      <url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
      <distribution>repo</distribution>
    </license>
  </licenses>

  <developers>
    <developer>
      <name>Jose Antonio Espinosa</name>
      <email>[email protected]</email>
      <organization>Nomorepass</organization>
      <organizationUrl>https://nomorepass.com</organizationUrl>
    </developer>
  </developers>

  <scm>
    <connection>scm:git:git://github.com/yoprogramo/nomorepass-java.git</connection>
    <developerConnection>scm:git:ssh://github.com:yoprogramo/nomorepass-java.git</developerConnection>
    <url>https://github.com/yoprogramo/nomorepass-java/tree/master</url>
</scm>

Y, una vez informado de todo esto, hay que incluir los plugins que nos permitirán hacer el despliegue directamente. Yo añadí esto:

<distributionManagement>
    <snapshotRepository>
      <id>ossrh</id>
      <url>https://oss.sonatype.org/content/repositories/snapshots</url>
    </snapshotRepository>
    <repository>
      <id>ossrh</id>
      <url>https://oss.sonatype.org/service/local/staging/deploy/maven2/</url>
    </repository>
</distributionManagement>

Y puse en mi directorio de maven settings.xml los datos de mi usuario

<settings>
  <servers>
    <server>
      <id>ossrh</id>
      <username>xxxxxxxxxx</username>
      <password>xxxxxxxxxx</password>
    </server>
  </servers>
</settings>

Por último, toda la sección de build (que no tenía) la sustituí por esto:

  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-gpg-plugin</artifactId>
        <executions>
          <execution>
            <id>sign-artifacts</id>
            <phase>verify</phase>
            <goals>
              <goal>sign</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.sonatype.plugins</groupId>
        <artifactId>nexus-staging-maven-plugin</artifactId>
        <version>1.6.7</version>
        <extensions>true</extensions>
        <configuration>
          <serverId>ossrh</serverId>
          <nexusUrl>https://oss.sonatype.org/</nexusUrl>
          <autoReleaseAfterClose>true</autoReleaseAfterClose>
        </configuration>
      </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-source-plugin</artifactId>
          <version>2.2.1</version>
          <executions>
            <execution>
              <id>attach-sources</id>
              <goals>
                <goal>jar-no-fork</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
        <plugin>
          <groupId>org.apache.maven.plugins</groupId>
          <artifactId>maven-javadoc-plugin</artifactId>
          <version>2.9.1</version>
          <executions>
            <execution>
              <id>attach-javadocs</id>
              <goals>
                <goal>jar</goal>
              </goals>
            </execution>
          </executions>
        </plugin>
    </plugins>
</build>

Y ya, finalmente, pude ejecutar el mágico:

mvn clean deploy

Si todo ha ido bien, el artefacto estará subido a un repositorio que tendremos que promocionar a «Release» para que se sincronice con el repositorio central… Pero al final ya lo tendremos disponible para todo el mundo…

Aquí podéis encontrar lo que acabo de subir: https://search.maven.org/artifact/com.nomorepass/nomorepass/1.0/jar

Construyendo un dispositivo inteligente con nodemcu y un display OLED

Últimamente se están poniendo de moda los dispositivos «inteligentes» que, básicamente, consiste en cacharros que están conectados de una manera o de otra a internet o a nuestra red doméstica y que aceptan comandos desde la red para controlar sus distintas funciones.

La verdad es que han bajado mucho de precio y el poder controlarlas desde los distintos asistentes de voz le dan un extra adicional. He trasteado un poco con Alexa y con Google Home, pero todavía estoy en el proceso de encontrarle el sitio correcto. En cualqueir caso, como soy un alma inquieta he preferido ver cuanto me costaba crear mi propio «dispositivo inteligente» con los materiales que tenía a mano… Esto es lo que he usado:

  • Pantalla OLED de 1,3″ con el chip SSH1106 de 128×64. En concreto esta.
  • Una placa Weimos D1 mini (compatible), que se basa en el chip ESP8266. En concreto esta.
  • Un relé preparado para 5V. En mi caso este.

El chip ESP8266 es una maravilla que integra wifi junto con un microcontrolador que puede ser programado desde el IDE del Arduino (entre otras formas) y el empaquetado en forma de placa nocemcu hace que sea muy sencillo hacer proyectos con este, siendo más barato y más potente que un arduino habitual. De hecho los componentes de este proyecto comprados en aliexpress (quitando cables y gastos de envío) no suman más de 6 Euros… Irresistible para montar un prototipo.

Al lío… Es esquema de conexiones es este:

En realidad el pulsador no hace falta, lo he incluido para poder comunicar al dispositivo manualmente el cambio de estado (es un rollo tener que hacerlo todo en remoto) y no es necesario para la primera versión.

Para poder programar la placa desde el IDE del Arduino vamos a tener que ir a la sección de Archivo->Preferencias y añadir la url http://arduino.esp8266.com/stable/package_esp8266com_index.json en el campo Gestor de URLs Adicionales de Tarjetas, quedando como en la imagen:

Luego nos vamos a Herramientas->Placas->Gestión de tarjetas y buscamos ESP8266 e instalamos la versión de ESP8266 Community.

Con esto ya nos aparecerá el tipo de tarjeta Wemos o NodeMCU en la lista de tarjetas que podemos conectar con el IDE.

Lo siguiente es encontrar una librería que nos permita interactuar por I2C con nuestra pantalla (y que sea lo más flexible posible para usos futuros). Esto es lo que me llevó más tiempo, básicamente porque los ejemplos que proporcionan están preparados para otro chip y la nomenclatura de los pines es diferente… Al final la mejor es esta:

https://github.com/ThingPulse/esp8266-oled-ssd1306

Yo he usado como base el ejemplo que viene al instalar la placa y se llama WIFIServer (creo que lo han cambiado por una versión nueva, os dejo el código completo al final de todas formas). El funcionamiento es de tal manera que al arrancar se conecta a la red wifi que tengamos configurada y queda esperando conexiones, cuando recibe una petición https://server_ip/gpio/0 ponemos a cero el GPIO2 y si recibimos una https://server_ip/gpio/1 lo ponemos a 1… Como esa salida la tenemos conectada al relé, pues ya podemos encender o apagar lo que queramos desde la web.

Para sacar la información por la pantalla, básicamente, utilizo la función drawString que me imprime en las coordenadas dadas de la pantalla una cadena (y en la fuente que hayamos seleccionado antes)… Podéis verlo en funcionamiento en este video:

Os pongo el código antes de integrar lo del botón… Básicamente lo que falta por poner es que cuando detectemos una pulsación del botón (D3 pase a cero) cambiemos el estado del pin conectado al relé (así tenemos control manual, cosa que echo de menos en las bombillas inteligentes, por ejemplo).


#include <ESP8266WiFi.h>
#include "SH1106Wire.h"

const char* ssid = "tussid";
const char* password = "tupassword";

SH1106Wire display(0x3c, 4, 5);

WiFiServer server(80);

void setup() {
 
  Serial.begin(115200);
  delay(10);

  pinMode(2, OUTPUT);
  digitalWrite(2, 0);
  
  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  display.init();
  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_10);

  display.clear();
  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.drawString(0,0,"Connecting...");
  display.display();
      
  WiFi.begin(ssid, password);
  
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.println("WiFi connected");
  
  display.clear();
  display.drawString(0,0,String(ssid));
  display.drawString(0,10, "IP: "+WiFi.localIP().toString());
  display.display();
    
  // Start the server
  server.begin();
  Serial.println("Server started");

  // Print the IP address
  Serial.println(WiFi.localIP());
}

void loop() {
  WiFiClient client = server.available();
  if (!client) {
    return;
  }
  
  Serial.println("new client");
  while(!client.available()){
    delay(1);
  }
  
  String req = client.readStringUntil('\r');
  Serial.println(req);
  client.flush();
  
  int val;
  if (req.indexOf("/gpio/0") != -1)
    val = 0;
  else if (req.indexOf("/gpio/1") != -1)
    val = 1;
  else {
    Serial.println("invalid request");
    client.stop();
    return;
  }

  digitalWrite(2, val);
  display.setColor(BLACK);
  display.fillRect(0, 26, 100, 10);
  display.setColor(WHITE);
  display.drawString(0,26,"GPIO: "+String(val));
  display.display();
  
  client.flush();

  String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nGPIO is now ";
  s += (val)?"high":"low";
  s += "</html>\n";

  client.print(s);
  delay(1);
  Serial.println("Client disonnected");
}

Si habéis leido el código veréis que hay algunas cosas que se hacen de más, por ejemplo, pintamos un rectángulo en negro para borrar la línea antes de pintarla de nuevo con el valor del GPIO. Eso es debido a que esta librería está pensada para borrar la pantalla cada vez que la actualicemos y, por eso, no limpia el hueco en el que va a escribir (igual podemos hacer un fork que lo solucione, ya veremos) y sin esa limpieza las letras se escriben unas encima de otras.

Una nota final… El servidor no envía cabeceras CORS, por lo que si vais a utilizarlo desde javascript en cualquier otro servidor os saltará un error en la consola (y en mac ni siquiera hará la llamada real), en linux y windows funcionará aunque no recibiréis la respuesta.

Sigo modificando el código y demás a ver qué termino consiguiendo… Hasta es posible que le diseñe un PCB… Ya os iré contando.

Olvidarse de las contraseñas DEFINITIVAMENTE en Android

Una de las preguntas más redundantes que nos han hecho en los múltiples eventos en los que hemos presentado NoMorePass es ¿Puedo usarlo para hacer login en el propio móvil? Nuestra respuesta, como siempre, era positiva, pero con restricciones, hasta el momento solo podíamos copiar-pegar la contraseña… Y digo hasta ahora porque Android 8 incluyó una novedad que nos venía al pelo: el Autofill Framework.

Este framework permite a algunas aplicaciones registrarse como servicio proveedor de credenciales de forma que, si el usuario selecciona esa aplicación, el sistema permite que la aplicación «recomiende» valores posibles para los campos a rellenar en las aplicaciones… Dicho y hecho, esto es lo que los usuarios de NoMorePass nos estaban pidiendo y esto es lo que hemos conseguido (dentro video:)

Autocompletar con NoMorePass

Como véis es algo sumamente sencillo, seleccionar NoMorePass como proveedor de autocompletar y a partir de ese momento todas las contraseñas estarán disponibles para autorellenado cuando las necesitemos.

La primera vez que usamos una contraseña para una app nos preguntará qué contraseña enviar (y usaremos el mismo método que con las webs) y, lo que es más, si metemos a mano una contraseña se nos preguntará si queremos registrar esa contraseña en NoMorePass y así no tener que volver a meterla nunca más… Así hacemos realidad nuestro lema: Olvida tus contraseñas.

¿Y qué pasa con iOS? bueno, apple nunca nos ha puesto las cosas fáciles, más teniendo en cuenta su empeño con quedarse con las credenciales de todo el mundo en su iCloud. Sin embargo, a partir de iOS 12, Apple ha abierto un poco la mano a esta posibilidad y ofrece Servicios de autenticación que, cómo no, vamos a integrar lo antes que podamos.

Mientras… Si tienes Android 8.0 o superior, puedes disfrutar de esta nueva funcionalidad descargádote la versión 1.11.1 o superior de la app.

Creando extensiones para los navegadores

Como ya os he comentado, desarrollando mi nuevo proyecto NoMorePass, uno de los elementos fundamentales para que se usase la app era disponer de un plugin para el navegador que permitiese interceptar las páginas con usuario/password y entrar en las mismas con el protocolo seguro de NoMorePass. Aunque en principio solo quería hacer uno para demostrar lo que se podía hacer (el de chrome, por obvias razones), al final terminé desarrollando cinco para cubrir la mayoría de las necesidades. No voy a entrar en detalles ahora sobre la tecnología subyacente, lo que voy a hacer es contaros las principales diferencias entre cada uno de los ecosistemas para los que hice las extensiones y los problemas que nos vamos a encontrar.

Todas las extensiones que he programado han funcionado (que no es poco) y todas están en javascript, así que esa parte me la voy a saltar y voy a contaros los problemas que me encontré en orden cronológico.

Chrome

Aunque, a priori, creí que iba a ser el más complicado, porque partía de una base muy pobre en lo que a extensiones se refiere, al final no fue para tanto. La documentación que dispone en la web de developers de chrome es muy completa y con ejemplos que sirven para casi todo.

Probar la extensión es sencillo, solo hay que activar el modo desarrollador en la pestaña de extensiones y cargar el directorio en el que estamos trabajando… La depuración y lo demás es muy sencillo si estamos acostumbrados a inspeccionar o depurar páginas web.

La parte más «complicada» es cuando quieres distribuir la extensión. Hay una opción que te permite empaquetarla en un archivo .crx, peeeeeero, eso no sirve para nada ya que al abrir el crx con chrome te dice que no va a instalarte nada… Así que tienes que decirles a tus probadores que se descompriman el archivo y activen la parte de desarrollador (que es un rollo de explicar) o bien pasarlo al chrome web store… Es lo que hice y puedes dejar la extensión sin publicar para que lo usen tus probadores. Muy fácil y rápido. Eso si, te pueden banear la extensión (a mi me pasó) si la revisan y ven algo sospechoso. Lo bueno es que puedes explicar lo que pasa y como funciona y si todo está ok son muy rápidos en volverte a activar la extensión. Muy contento con esta parte.

Firefox

El segundo en preferencia es, como no, Firefox. Había oído que los .xpi ya estabán obsoletos y que ahora había que hacer extensiones más parecidas a las de chrome… Y tanto! El estandar webextension está bien documentado en la MDN y, el problema, es que no es un estándar maduro del todo. Está muy basado en las extensiones chrome a las que «copian» casi todo, por lo que es muy sencillo pasar de una a otra, pero con carencias importantes (que en mi caso me hicieron reescribir gran parte de la extensión). Lo prometedor del tema es que están avanzando y según los navegadores vayan incorporando las funcionalidades que faltan vamos a un escenario de muy, muy facil adaptación.

Mozilla te ofrece la función en el AMO (addons.mozilla.org) de subir tu extensión y que te la firmen para que la puedas dstribuir entre tus probadores sin que se queje mucho el navegador. Obviamente también puedes subirla a la página pública, pero ahí el tema varía mucho…. Subí una primera versión no del todo pulida y a los dos días me rechazaron la extensión y me dieron consejos para resubirla. Lo hice a los 30 minutos de recibir la respuesta pero, según lo que dicen, me metieron en la cola de revisión de los administradores y esa cola es EXAGERADAMENTE lenta. Hoy llevo ya 32 días esperando en esa cola y estoy todavía en el número 126:

A este paso a finales de mes igual tengo ya la extensión en la página de addons de Mozilla… Completamente desesperante.

Safari

A petición de mis amigos mac-queros estudié la posibilidad de realizar una extensión para Safari. Dejadme que os diga una cosa, es un puto infierno. Apple ha cambiado la forma de construir una extensión para que tengas que escribir parte del código en Xcode (Objective-c o swift) y otra parte en javascript y que tengas que utilizar un sistema infame de empaquetado para subirlo al itunes y que aparezca disponible. El caso es que lo hice, siguiendo todas sus intrucciones, y después de conseguir que funcionase en mi mac me encontré con la maraña de certificados, firmas, perfiles, etc. que me obligaron a cambiar el proyecto un poco… Con tan mala suerte que una vez subido a itunes resulta que no funcionaba ¡¡!!

Así que, recuperé la forma antigua de hacer las extensiones, puramente en javascript y con un esquema muy parecido a las de chrome y las webextensions y un empaquetado mucho más sencillo… Y generé un archivo que Safari puede instalar sin problemas y que puedo distribuir sin problemas… Una pena que Apple se empeñe con todo su alma en hacer las cosas difíciles a los desarrolladores.

Opera

Ya con todos los deberes hechos me pareció interesante ver el nivel de compatibilidad de las webextensions entre navegadores… Y decidí hacer la extensión para Opera. Mi sorpresa fue mayúscula cuando vi que la misma extensión de chrome funcionaba sin apenas cambios en opera (quité un par de cosas del manifest.json y poco más). Así que, ole por Opera! El proceso de publicación, no obstante, sigue siendo bajo revisión y tienes que subirlo (con mucha más info de la que deseaba) en https://addons.opera.com/developer/ y ahí sigue esperando revisión… El problema es que no se en qué puesto de la cola estoy ni cuanto tiempo va a tardar en llegar a estar disponible.

Edge

Y llegamos a la gran esperanza «windowsera», visto que, según la documentación, edge permitía un esquema muy parecido a las webextensions de firefox me lancé al ruedo y, con una máquina virtual de windows10 profesional, empecé a adaptar la extensión de firefox.

La definición correcta para las extensiones de Edge es: ¡niseteocurraporDios! Después de un montón de horas lidiando con actualizaciones del sistema, con cuelgues, con malos funcionamientos del sistema de depuración y con mi bisoñez en el sistema conseguí que la extensión funcionase en desarrollo en mi máquina… Bueno, ahora distribuirlo…

Pues no es tan sencillo, ni mucho menos, después de gastarme 90 euros (75+iva) en darme de alta como desarrollador de microsoft para reservarme el nombre de la aplicación y poder subirla a la tienda de windows.. Resulta que la tienda no admite extensiones. ¡¡¡¡¡!!!!! y, lo que es peor, para distribuir el appx que consigo generar tengo que firmarlo con unos certificados que no tengo y que solo se pueden generar con extraños comandos que no te explican de donde salen (si al menos te dijeran como hacerlo con openssl) y luego el usuario tiene que instalarse el certificado en su máquina antes de instalar la extensión.. En suma, no se cómo distribuir esta extensión ni si merece la pena….

Según microsoft esto es lo que pasa:

Así que hay que pedir por favor, por favor, que te tengan en cuenta en esta url: http://aka.ms/extension-request

Y esperando estoy…

 

 

NoMorePass

¿Alguna vez habéis sentido como que se os olvidaba algo importante? ¿y si ese algo era un password de los que podías necesitar en cualquier momento? ¿y si el proceso para recuperar el password perdido fuese tan tedioso y largo que le quitasen las ganas a cualquiera? ¿y si habéis perdido, lo que es peor, el password de la cuenta de correo con la que teníais ligada esa password rebelde?

Todos esos problemas, y más me acuciaban día si y día también. Para asegurar tendía a poner el mismo password (o variaciones triviales) en todos los servicios en los que me registraba que eran, por cierto, incontables… Que si foros, que si demos, que si nuevos servicios, que si sitios oficiales, que si… Total, que al final solo confiaba en mi navegador para que me guardase los passwords, peeeeero, ¿y si alguien me pedía un rato el ordenador para cualquier cosa? ¿tendría acceso a mis passwords? Claro que si, por eso es tan seguro dejar el password en el navegador como en pos-it pegado en la pantalla… Un desastre, vamos.

Hablando, además, con un sobrino mío que también utilizaba el método de tener una libreta con todos los passwords (pues anda que no pierdo yo libretas, o que no son propensas a ser hojeadas por cualquier visitante inesperado), llegué a la conclusión de que debía hacer algo… Y lo he hecho, se llama nomorepass y te permite guardar de manera segura todas tus contraseñas en tu móvil, protegidas por una contraseña maestra y/o los sistemas biométricos (huella) del dispositivo y, lo que es mejor, te permite olvidarte de ellos sin problema, ¿cómo? Muy sencillo, nunca más tendrás que teclear un password, así que nunca te inportará qué password es y, por eso, podrás generar un password distinto para ca web o servicio, que ya se encarga el móvil de guardarlo y enviarlo a quien lo necesite.

¿Es seguro? 

Un montón, es imposible interceptar los datos necesarios para recomponer la password que estás usando.

Además, podrás sacar una copia de seguridad de tus passwords con la seguridad de que solo tu desde tu aplicación podrás volver a recuperarla, ya sea en tu teléfono o en otro nuevo (ya sabes, suele caer en sitios muy húmedos)

¿Es sencillo?

Apuntar con el movil a la pantalla y listo… No hay nada más facilito. Además, tendrás siempre contigo tus passwords, sin importar en qué ordenador estés.

Pero entonces, ¿me tengo que fiar de tus servidores?

No, te recomiendo que no te fies de nadie, ni siquiera de mi. Tus passwords nunca salen de tu móvil (al menos nunca en claro) y no se pueden almacenar en otro sitio y nunca está la clave de encriptación junto a los datos encriptados (ni siquiera en los backups)… Así que, no, no te fíes. Simplemente usa la app y se dueño de tus passwords, se acabaron los hackeos, filtraciones y demás problemas.

Me mola… ¿Qué hago para probarlo?

Directo a https://www.nomorepass.com allí tienes todos los enlaces e instrucciones…