# Soporta verificación NIP-05 de Nostr en tu propio dominio

## Introducción a Nostr

Si nunca has utilizado Nostr necesitarás entender algunos conceptos claves.

Lo primero que tienes que comprender es que Nostr es un **protocolo** diseñado para enviar mensajes –notas, principalmente– a través de Internet.

{% hint style="info" %}
**Nostr** es el acrónimo de la frase en inglés *“Notes and Other Stuff Transmitted by Relays", que se puede traducir por "Notas y otras cosas transmitidas por relés".*&#x20;
{% endhint %}

Nostr es código libre, un protocolo sencillo –de ahí su genialidad y resiliencia– y abierto, de forma que cualquiera puede participar, implementar o construir sobre el mismo.&#x20;

Fue diseñado por [`fiatjat_`](https://github.com/fiatjaf) como un protocolo descentralizado para crear redes sociales incensurables al no existir una entidad centralizada que pueda prohibir o censurar algo. &#x20;

{% hint style="danger" %}
Aunque es descentralizado no se basa en p2p o en tecnología blockchain.
{% endhint %}

Los usuarios interactúan con el protocolo a través de un <mark style="color:red;">**cliente**</mark> –web, app, aplicación de escritorio, etc.– y publican notas firmadas digitalmente y con un sello temporal haciendo uso de criptografía asimétrica. Al tratarse de un protocolo abierto y sencillo, cualquiera puede programar su propio cliente. De hecho, existen muchos clientes, lo que es magnífico, dado que evita el monopolio y, por ende, la censura.&#x20;

Las notas son enviadas por el cliente del usuario hacia un conjunto de <mark style="color:red;">**relés**</mark> o <mark style="color:red;">**retransmisores**</mark>, también sencillos de implementar. Los retransmisores –relays, en inglés– proporcionan el almacenamiento y retransmisión de las notas. Cualquiera puede correr su propio retransmisor, lo que de nuevo garantiza la resiliencia del protocolo. Lo interesante aquí es que no necesitamos confiar en los relés, ya que la verificación de las notas se hace en el lado cliente. Además, podemos cambiar o añadir nuevos relés en cualquier momento. En la siguiente ilustración se aprecia la idea de múltiples relés o retransmisores para que los usurios de Nostr puedan comunicarse. Notad que, para ver los mensajes el uno del otro necesitan utilizar un mismo relé.

<figure><img src="https://2243369426-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs6bSrMmlc7N1AYvkGEO3%2Fuploads%2FttOaYPiu8qakmYzE0bId%2FNostr_infraestructura.png?alt=media&#x26;token=443f8278-4940-449a-92f3-54db3ca27997" alt=""><figcaption><p>Bob y Alice necesitan comunicarse a través de un relé común, en este caso el relé nº 2. </p></figcaption></figure>

La firma y sellado temporal de las notas impide su manipulación o falsificación, garantizando su integridad y autenticidad. Se pueden verificar  a través de la clave pública de su autor, esta clave pública identifica al autor, es posible buscar un usuario en Nostr a través de su clave pública.

Mi clave pública en Nostr es <mark style="color:blue;">`npub1hhml4uqkctuqdeuegg6ckvkt53ggkm84jgvy640e7spz6085aq0qlsmu6k`</mark>, un tanto farragosa y complicada de recordar, pero para eso existen los alias o *nick-names*, el mío es [<mark style="color:green;">**Sec\_Adviser**</mark>](https://primal.net/p/npub1hhml4uqkctuqdeuegg6ckvkt53ggkm84jgvy640e7spz6085aq0qlsmu6k). Si pulsas sobre mi alias, verás mi perfil en el cliente web [primal.net](https://primal.net/) de forma similar a como se aprecia en la siguiente ilustración. Quizás notes que mi usuario tiene una marca de verificación similar a la marca de verificación que muestra la red social X, antes conocida como Twitter.

<figure><img src="https://2243369426-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs6bSrMmlc7N1AYvkGEO3%2Fuploads%2FYmsSkIpqAvuZtXQYv1ZW%2Fcheck-mark_Nostr.jpg?alt=media&#x26;token=1b15c18b-473a-4996-bfe6-5e2de274018d" alt=""><figcaption><p>Perfil de <code>Sec_Adviser</code> en el cliente Nostr de <a href="https://primal.net"><code>primal.net</code></a>, notad la marca de verificación conforme nip05.</p></figcaption></figure>

Vamos a aprender a obtener la marca de verificación implementando nip05 en vuestro propio dominio y servidor.

## Eventos del protocolo

Podríamos decir que en el protocolo Nostr solo existe un tipo de objeto: el evento. Los usuarios publican eventos de distintos tipos, con un sello temporal y firmados criptográficamente con la clave privada del usuario.&#x20;

Las [NIPs](https://github.com/nostr-protocol/nips) –Nostr Implementation Possibilities– son el estándar que define la implementación mínima que debe respetar cualquiera que pretenda interactuar con el protocolo, al tiempo que facilita extender sus capacidades mediante la adición de nuevos NIPs. En los NIPs existen partes de implementación obligatoria y partes opcionales. El formato de un evento conforme [nip01](https://github.com/nostr-protocol/nips/blob/master/01.md) se define tal que, se cita literal:

```json
// Formato de un evento Nostr
{
  "id": <32-bytes lowercase hex-encoded sha256 of the serialized event data>,
  "pubkey": <32-bytes lowercase hex-encoded public key of the event creator>,
  "created_at": <unix timestamp in seconds>,
  "kind": <integer between 0 and 65535>,
  "tags": [
    [<arbitrary string>...],
    // ...
  ],
  "content": <arbitrary string>,
  "sig": <64-bytes lowercase hex of the signature of the sha256 hash of the serialized event data, which is the same as the "id" field>
}
```

Vamos a explicar el formato de un evento sobre un par de ejemplos reales, de forma que espero sea más didáctico y sencillo de entender. Si buscáis mi usuario –en base a mi clave pública que ya conocéis– en [Nostr.band](https://nostr.band/?q=npub1hhml4uqkctuqdeuegg6ckvkt53ggkm84jgvy640e7spz6085aq0qlsmu6k), obtendréis un resumen de mi perfil y los últimos resultados o notas publicadas por mí, algo similar a lo que se aprecia en la siguiente ilustración.

<figure><img src="https://2243369426-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs6bSrMmlc7N1AYvkGEO3%2Fuploads%2FsSwlI3lXuJbYtkzBDTp0%2Fnostr_band_nrespuesta.png?alt=media&#x26;token=10155051-95cb-4c30-b370-38fbd6bb2897" alt=""><figcaption><p>Última nota publicada en Nostr por el perfil Sec_Adviser, la llamaremos "nota_respuesta"</p></figcaption></figure>

La nota anterior la vamos a denominar <mark style="color:red;">**`nota_respuesta`**</mark>. Además, si bajas un poco más entre los resultados, verás que hay un mensaje previo tal que:

<figure><img src="https://2243369426-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs6bSrMmlc7N1AYvkGEO3%2Fuploads%2Ffe1JsA76qU4lT9fmuOSk%2Fnota_inicial.png?alt=media&#x26;token=4162cf2b-c3f8-41c0-9af5-35832b3f8cca" alt=""><figcaption><p>Nota a la que se respondía en el mensaje previo, la llamaremos "nota_inicial"</p></figcaption></figure>

Este último mensaje, que llamaremos <mark style="color:red;">**`nota_inicial`**</mark>, es un mensaje que publiqué 10 días atrás, en concreto el 18 de enero de 2024, mensaje al que he respondido hoy, 28 de enero, es por ello que el bocadillo de diálogo muestra un 1, indicando que hay una respuesta.&#x20;

Como el protocolo es muy sencillo, he utilizado unas librerías en Python para capturar estos dos eventos que hemos denominado <mark style="color:red;">`nota_inicial`</mark>y <mark style="color:red;">`nota_respuesta`</mark>. A continuación se muestran ambos eventos o notas con el formato original en el que viajan por la Internet.&#x20;

Primero el evento <mark style="color:red;">`nota_inicial`</mark>:

```json
// Evento "nota_inicial"
{
  "id": "cbfb2273264e1bb892236b24a1a1c0b65efad2856b5e704691e68360959b2c6b",
  "pubkey": "bdf7faf016c2f806e79942358b32cba4508b6cf592184d55f9f4022d3cf4e81e",
  "created_at": 1705600279,
  "kind": 1,
  "tags": [],
  "content": "Mensaje de prueba, para explicar el protocolo Nostr. Fecha: 18 enero 2024.",
  "sig": "604aa49495e036d1ed2bfb54f9c9b0103817df3bf4956d8e641507fe15df5a006857645a89a4553759e4bdae247eb97fda94eb2c701b540c9cb69504b944fa62"
}
```

Posteriormente, la respuesta dada a la nota previa en la <mark style="color:red;">`nota_respuesta`</mark>:

```json
// Evento "nota_respuesta"
{
  "id": "9ae0eb602be730065f172cd9fbfa0d5941779cd1265348823fae3581e1a46e19",
  "pubkey": "bdf7faf016c2f806e79942358b32cba4508b6cf592184d55f9f4022d3cf4e81e",
  "created_at": 1706445257,
  "kind": 1,
  "tags": [
    [
      "e",
      "cbfb2273264e1bb892236b24a1a1c0b65efad2856b5e704691e68360959b2c6b",
      "",
      "root"
    ],
    [
      "p",
      "bdf7faf016c2f806e79942358b32cba4508b6cf592184d55f9f4022d3cf4e81e"
    ]
  ],
  "content": "Me respondo a mí mismo para ver el formato de evento Nostr en una respuesta.",
  "sig": "444dca6e94e4d43eba778f2b3b3a1cb25f39209fb0f8a0c626dd64aa16b22d1214f0341eace4cd116ca5bcb8eb91307fd90cb54b78251d13ab24e497ab4731f6"
}
```

Vamos a ver uno a uno los campos de un evento:

* <mark style="color:yellow;">**ID:**</mark> un identificador del evento.
* <mark style="color:yellow;">**Pubkey:**</mark>  la clave pública del autor codificada en hexadecimal, 32 octetos de longitud.&#x20;
* <mark style="color:yellow;">**Created\_at:**</mark> fecha en formato `epoch`, habitual de UNIX, `epoch` es el número de segundos transcurridos desde el 1 de enero de 1970 a las 00:00:00 UTC.&#x20;
* <mark style="color:yellow;">**Kind:**</mark> especifica cómo los clientes deben interpretar el propio evento y los campos que incluye. Un NIP puede especificar un nuevo tipo de kinds. Se trata de un entero de 16 bits, de forma que puede tomar 65536 valores distintos, pero vamos a los dos más básicos:
  * <mark style="color:red;">**0:**</mark> `metadatos`: en este tipo de eventos se incluye información en el campo "content" con en un formato que es la representación de un objeto json vía un tipo cadena –string–.
  * <mark style="color:red;">**1:**</mark> `nota de texto: son`mensajes en texto plano, como un tuit.
* <mark style="color:yellow;">**Tags:**</mark> las etiquetas permiten relacionar un evento con otro evento o usuario, añadir enlaces o contenidos multimedia.&#x20;
* <mark style="color:yellow;">**Content:**</mark> texto arbitrario, el mensaje.&#x20;
* <mark style="color:yellow;">**Sig:**</mark> firma criptográfica en hexadecimal del resultado de calcular el resumen criptográfico sha 256 del resto de campos de la nota.

Tanto en la <mark style="color:red;">**`nota_inicial`**</mark> como en la <mark style="color:red;">**nota\_respuesta**</mark> el campo <mark style="color:yellow;">**ID**</mark> son distintos, esto es normal, ya que identifican de forma única a cada evento y esto permite, por ejemplo, buscar un evento concreto por su id. <br>

El campo <mark style="color:yellow;">**pubkey**</mark> es idéntico en ambas notas, es lo esperado ya que ambos han sido creados por mí y necesitas poder identificar al autor y conocer su clave pública para poder verificar la autenticidad e integridad del mensaje. La clave pública está codificada en hexadecimal. Puedes obtener tu clave pública en hexadecimal en [Nostr.band](https://nostr.band/?q=npub1hhml4uqkctuqdeuegg6ckvkt53ggkm84jgvy640e7spz6085aq0qlsmu6k) escogiendo "Copy pubkey" como se aprecia en la siguiente ilustración.

<figure><img src="https://2243369426-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs6bSrMmlc7N1AYvkGEO3%2Fuploads%2F6OfEHxW97I8YOdXSw4IN%2Fhexadecimal.png?alt=media&#x26;token=004170f8-0983-4aa1-a3da-415487975be7" alt=""><figcaption><p>El sitio Nostr.band permite obtener la clave pública de un perfil en formato hexadecimal.</p></figcaption></figure>

En <mark style="color:red;">**`nota_inicial`**</mark> el campo <mark style="color:yellow;">**created\_at**</mark> vale **1705600279**, mientras que en <mark style="color:red;">**`nota_respuesta`**</mark> el valor es **1706445257**. Podemos convertir ese valor en segundos a una fecha fácilmente con el comando [<mark style="color:green;">`date`</mark>](#user-content-fn-1)[^1] en Linux y/o MacOS así:

<figure><img src="https://2243369426-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2Fs6bSrMmlc7N1AYvkGEO3%2Fuploads%2FQkSROOG22WzFvrjbhNb5%2Fepoch_time.png?alt=media&#x26;token=9615c55b-27bf-4c05-b5f0-124a51bcdf11" alt=""><figcaption><p>Podemos decodificar una fecha en formato epoch time en un Mac con <code>date -r valor_formato_epoch-time</code></p></figcaption></figure>

En ambos eventos el valor de la clave <mark style="color:yellow;">**kind**</mark> es 1, lo que significa que son notas o eventos de texto cuyo contenido viaja en el campo <mark style="color:yellow;">**content**</mark>.

En <mark style="color:red;">**nota\_inicial**</mark> la clave <mark style="color:yellow;">**tags**</mark> no tiene valores asociados, sin embargo, en la <mark style="color:red;">**nota\_respuesta**</mark> el campo o clave <mark style="color:yellow;">**tags**</mark> sí tiene valores asignados, esto ocurre porque es una respuesta a otro evento. A continuación el contenido de <mark style="color:yellow;">**tags**</mark> en la <mark style="color:red;">**nota\_respuesta**</mark>:

```json
// Valor campo tags en nota_respuesta:
"tags": [
    [
      "e",
      "cbfb2273264e1bb892236b24a1a1c0b65efad2856b5e704691e68360959b2c6b",
      "",
      "root"
    ],
    [
      "p",
      "bdf7faf016c2f806e79942358b32cba4508b6cf592184d55f9f4022d3cf4e81e"
    ]
  ],
```

El primer valor de <mark style="color:yellow;">**tags**</mark> es una **"e"** –etiqueta utilizada para referenciar a otro evento– que indica que el evento actual está relacionada con otro evento con <mark style="color:yellow;">**id**</mark> <mark style="color:blue;">`cbfb2273264e1bb892236b24a1a1c0b65efad2856b5e704691e68360959b2c6b`</mark>, justamente el <mark style="color:yellow;">**id**</mark> del evento <mark style="color:red;">**nota\_inicial**</mark>, y es que recoordemos que <mark style="color:red;">**nota\_respuesta**</mark> es una respuesta a <mark style="color:red;">**nota\_inicial**</mark>. Hay una segunda etiqueta añadida, **"p"** –utilizada para referenciar a otro usuario–**,** que indica este evento está relacionado con alguien identificado por la clave pública <mark style="color:blue;">bdf7faf016c2f806e79942358b32cba4508b6cf592184d55f9f4022d3cf4e81e</mark>, que es mi clave pública en formato hexadecimal. Tanto "e" como "p" son consideradas etiquetas estándar. Hay otra etiqueta  estándar, "a", que referencia a eventos reemplazables, pero no la veremos aquí, por ahora.

Para finalizar el campo o clave <mark style="color:yellow;">**content**</mark> contiene los mensajes o notas en texto plano y el campo <mark style="color:yellow;">**sig**</mark> la firma criptográfica que protege la integridad del mensaje de forma que puede comprobarse si es íntegro, quién y cuándo lo emitió.

## Implementación verificación nip-05

En este apartado aprenderemos a implementar la verificación en Nostr o, en jerga técnica, como implementar [NIP-05](https://github.com/nostr-protocol/nips/blob/master/05.md), especificación que, en pocas palabras, mapea las npub o claves públicas que identifican de forma única a un usuario de Nostr a identificadores de internet basados en DNS (a un correo electrónico, para que lo entiendas mejor, que no deja de ser otro identificador único). Si implementamos correctamente esta mejora, en tu perfil Nostr que aparecerá al utilizar cualquier cliente Nostr y buscar tu npub, podrás observar el tick de verificación junto a tu correo electrónico.

La implementación será sobre un servidor web basado en <mark style="color:red;">NGINX</mark>. La lógica de aplicación que nos demanda [NIP-05](https://github.com/nostr-protocol/nips/blob/master/05.md) la desarrollaremos usando un lenguaje de scripting ligero y rápido conocido como <mark style="color:yellow;">**LUA**</mark>, lenguaje que por sus características es ideal para ser embebido en otras aplicaciones, como Roblox, Nmap, Apache HTTP Server o nuestro servidor <mark style="color:red;">NGINX.</mark>

El código fuente en <mark style="color:yellow;">**LUA**</mark> y la configuración del servidor web <mark style="color:red;">NGINX</mark> la podéis encontrar en mi **repositorio Github**, a saber:

[GitHub - cokesaeba/nostr\_NIP-05](https://github.com/cokesaeba/nostr_NIP-05)

Este repositorio contiene toda la lógica de aplicación en <mark style="color:yellow;">**LUA**</mark> necesaria para implementar la verificación [NIP-05](https://github.com/nostr-protocol/nips/blob/master/05.md) en Nostr, así como los archivos de configuración necesarios que sirven como modelo para instalar tu propio servidor <mark style="color:red;">NGINX</mark>, en el que puedes configurar tu propio dominio. Aquí puedes encontrar ejemplos funcionales, con comentarios detallados, para configurar tu propio entorno.

Además, os voy a contar todo de una forma mucho más amena en un vídeo de apenas 45' en el que veremos:&#x20;

* Breve introducción.
* Fundamentos de Nostr.
* Eventos del protocolo.
* Implementación verificación [NIP-05](https://github.com/nostr-protocol/nips/blob/master/05.md) en <mark style="color:yellow;">**LUA**</mark> en <mark style="color:green;">**CLI**</mark> y sobre servidor web <mark style="color:red;">NGINX</mark>.

Con lo que has aprendido hasta el momento, estás más que capacitado para entender el vídeo, aunque... no te preocupes, repaso todo desde el principio y lo explicaré de forma muy práctica y con ejemplos. Sin más demora, adelante vídeo...<br>

{% embed url="<https://youtu.be/DLZkSefmx6Y>" %}
Vídeo en el que de forma práctica aprenderemos qué es **Nostr** y cómo implementar **NIP-05** en tu propio servidor NGINX.
{% endembed %}

Espero que hayas disfrutado con el artículo y el vídeo. Ya conoces mi npub por si quieres seguirme o comentar algo.

Nos vemos en Nostr... ¡únete a la resistencia, te esperamos!

[^1]: En Linux el comando equivalente sería:

    date -d @1705600279&#x20;
