Nostr.NIP05 (Nostr Lib v0.2.1) (nip05)

View Source

NIP-05: Mapping Nostr keys to DNS-based internet identifiers.

This module provides utilities for parsing, validating, and verifying NIP-05 identifiers (email-like addresses that map to Nostr public keys).

Local Functions (no HTTP required)

  • parse/1 - Split identifier into local-part and domain
  • valid?/1 - Check if identifier format is valid
  • verification_url/1 - Build the .well-known URL for verification
  • display/1 - Format identifier for display (handles _@domain -> domain)

HTTP Verification (requires :req dependency)

  • resolve/1 - Fetch pubkey and relays from .well-known endpoint
  • verify/2 - Verify identifier matches expected pubkey

Defined in NIP-05

Summary

Types

Domain part of identifier (after @)

Local part of identifier (before @)

NIP-05 identifier (e.g., bob@example.com)

Hex-encoded public key

Functions

Format a NIP-05 identifier for display.

Parse a NIP-05 identifier into its local-part and domain components.

Resolve a NIP-05 identifier to its pubkey and optional relay list.

Check if a NIP-05 identifier has valid format.

Build the well-known verification URL for a NIP-05 identifier.

Verify that a NIP-05 identifier resolves to the expected pubkey.

Types

domain()

@type domain() :: String.t()

Domain part of identifier (after @)

local_part()

@type local_part() :: String.t()

Local part of identifier (before @)

nip05_id()

@type nip05_id() :: String.t()

NIP-05 identifier (e.g., bob@example.com)

pubkey()

@type pubkey() :: String.t()

Hex-encoded public key

Functions

display(identifier)

@spec display(nip05_id()) :: String.t()

Format a NIP-05 identifier for display.

Per NIP-05, the identifier _@domain is the "root" identifier and should be displayed as just domain.

Examples

iex> Nostr.NIP05.display("bob@example.com")
"bob@example.com"

iex> Nostr.NIP05.display("_@bob.com")
"bob.com"

parse(identifier)

@spec parse(nip05_id()) :: {:ok, local_part(), domain()} | {:error, String.t()}

Parse a NIP-05 identifier into its local-part and domain components.

Examples

iex> Nostr.NIP05.parse("bob@example.com")
{:ok, "bob", "example.com"}

iex> Nostr.NIP05.parse("_@domain.com")
{:ok, "_", "domain.com"}

iex> Nostr.NIP05.parse("invalid")
{:error, "missing @ separator"}

resolve(identifier, opts \\ [])

@spec resolve(
  nip05_id(),
  keyword()
) :: {:ok, pubkey(), [String.t()]} | {:error, String.t()}

Resolve a NIP-05 identifier to its pubkey and optional relay list.

Makes an HTTP request to the domain's .well-known/nostr.json endpoint. Redirects are disabled per NIP-05 security requirements.

Returns {:ok, pubkey, relays} where pubkey is the hex-encoded public key and relays is a list of relay URLs (may be empty).

Requires the :req dependency.

Options

Any options are passed to Req.get/2. Useful for testing with :plug option.

Examples

# Assuming bob@example.com exists and returns valid data:
{:ok, "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9", ["wss://relay.example.com"]}

valid?(identifier)

@spec valid?(nip05_id()) :: boolean()

Check if a NIP-05 identifier has valid format.

The local-part must contain only a-z, 0-9, ., _, or - characters (case-insensitive). The domain must be non-empty.

Examples

iex> Nostr.NIP05.valid?("bob@example.com")
true

iex> Nostr.NIP05.valid?("alice_123@domain.co")
true

iex> Nostr.NIP05.valid?("_@bob.com")
true

iex> Nostr.NIP05.valid?("Bob!@example.com")
false

verification_url(identifier)

@spec verification_url(nip05_id()) :: {:ok, URI.t()} | {:error, String.t()}

Build the well-known verification URL for a NIP-05 identifier.

Examples

iex> {:ok, url} = Nostr.NIP05.verification_url("bob@example.com")
iex> URI.to_string(url)
"https://example.com/.well-known/nostr.json?name=bob"

iex> {:ok, url} = Nostr.NIP05.verification_url("_@domain.com")
iex> URI.to_string(url)
"https://domain.com/.well-known/nostr.json?name=_"

verify(identifier, expected_pubkey, opts \\ [])

@spec verify(nip05_id(), pubkey(), keyword()) :: :ok | {:error, String.t()}

Verify that a NIP-05 identifier resolves to the expected pubkey.

Returns :ok if the identifier resolves to the given pubkey, or {:error, reason} otherwise.

Requires the :req dependency.

Options

Any options are passed to resolve/2. Useful for testing with :plug option.

Examples

# Verify bob@example.com maps to the expected pubkey:
:ok = Nostr.NIP05.verify("bob@example.com", "b0635d6a9851d3aed0cd6c495b282167acf761729078d975fc341b22650b07b9")

# Mismatch returns error:
{:error, "pubkey mismatch"} = Nostr.NIP05.verify("bob@example.com", "wrong_pubkey")