Nostr.NIP17 (Nostr Lib v0.2.1) (nip17)

View Source

NIP-17 Private Direct Messages convenience functions

High-level API for sending and receiving encrypted private messages using the NIP-44 encryption and NIP-59 gift wrap protocol.

This module provides a simple interface on top of the lower-level primitives:

Defined in NIP 17 https://github.com/nostr-protocol/nips/blob/master/17.md

Summary

Functions

receive_dm(gift_wrap, recipient_seckey)

@spec receive_dm(Nostr.Event.GiftWrap.t() | Nostr.Event.t(), binary()) ::
  {:ok, Nostr.Event.PrivateMessage.t()} | {:error, atom()}

Receive a private direct message

Unwraps a gift wrap to extract and parse the private message. Validates that the sender pubkey in the rumor matches the seal's signer.

Arguments

  • gift_wrap - a GiftWrap struct or raw Event
  • recipient_seckey - recipient's secret key (hex-encoded)

Returns

  • {:ok, private_message} on success
  • {:error, reason} on failure

Example

{:ok, message} = Nostr.NIP17.receive_dm(gift_wrap, recipient_seckey)
IO.puts(message.content)

receive_file(gift_wrap, recipient_seckey)

@spec receive_file(Nostr.Event.GiftWrap.t() | Nostr.Event.t(), binary()) ::
  {:ok, Nostr.Event.FileMessage.t()} | {:error, atom()}

Receive a private file message

Unwraps a gift wrap to extract and parse the file message. Validates that the sender pubkey in the rumor matches the seal's signer.

Arguments

  • gift_wrap - a GiftWrap struct or raw Event
  • recipient_seckey - recipient's secret key (hex-encoded)

Returns

  • {:ok, file_message} on success
  • {:error, reason} on failure

Example

{:ok, file_msg} = Nostr.NIP17.receive_file(gift_wrap, recipient_seckey)
IO.puts(file_msg.file_url)

receive_message(gift_wrap, recipient_seckey)

@spec receive_message(Nostr.Event.GiftWrap.t() | Nostr.Event.t(), binary()) ::
  {:ok, Nostr.Event.PrivateMessage.t() | Nostr.Event.FileMessage.t(), binary()}
  | {:error, atom()}

Receive any NIP-17 message (kind 14 or 15)

Unwraps a gift wrap and returns the appropriate message type based on the kind.

Returns

  • {:ok, message, sender_pubkey} on success where message is PrivateMessage or FileMessage
  • {:error, reason} on failure

send_dm(sender_seckey, receiver_pubkeys, content, opts \\ [])

@spec send_dm(binary(), [binary()], binary(), Keyword.t()) ::
  {:ok, [Nostr.Event.GiftWrap.t()]} | {:error, term()}

Send a private direct message

Creates a kind 14 private message, seals it with the sender's key, and gift wraps it for each receiver plus the sender (for sent folder).

Arguments

  • sender_seckey - sender's secret key (hex-encoded)
  • receiver_pubkeys - list of receiver public keys (hex-encoded)
  • content - plain text message content
  • opts - optional arguments:
    • :reply_to - event ID this message is replying to
    • :subject - conversation title
    • :quotes - list of quoted event references
    • :created_at - timestamp for the inner rumor (default: now)

Returns

{:ok, gift_wraps} where gift_wraps is a list of GiftWrap structs, one for each receiver plus one for the sender.

Example

{:ok, gift_wraps} = Nostr.NIP17.send_dm(
  sender_seckey,
  [recipient_pubkey],
  "Hello, this is a private message!",
  subject: "Greeting"
)
# Publish each gift wrap to appropriate relays

send_file(sender_seckey, receiver_pubkeys, file_url, file_metadata, opts \\ [])

@spec send_file(binary(), [binary()], binary(), map(), Keyword.t()) ::
  {:ok, [Nostr.Event.GiftWrap.t()]} | {:error, term()}

Send a private file message

Creates a kind 15 file message with encryption metadata, seals it with the sender's key, and gift wraps it for each receiver plus the sender.

Arguments

  • sender_seckey - sender's secret key (hex-encoded)
  • receiver_pubkeys - list of receiver public keys (hex-encoded)
  • file_url - URL of the encrypted file
  • file_metadata - map with file encryption metadata (see FileMessage.create/5)
  • opts - optional arguments:
    • :reply_to - event ID this message is replying to
    • :subject - conversation title
    • :created_at - timestamp for the inner rumor (default: now)

Returns

{:ok, gift_wraps} where gift_wraps is a list of GiftWrap structs.

Example

{:ok, gift_wraps} = Nostr.NIP17.send_file(
  sender_seckey,
  [recipient_pubkey],
  "https://example.com/file.enc",
  %{
    file_type: "image/jpeg",
    encryption_algorithm: "aes-gcm",
    decryption_key: "key123",
    decryption_nonce: "nonce456",
    hash: "abc123"
  }
)