Documentation
¶
Index ¶
- Constants
- Variables
- func CanServeProtectedEvent(evt nostr.Event, authedPubkey string) bool
- func CleanupClient(client nostr.ClientInterface)
- func ClearChallengeForConnection(client nostr.ClientInterface)
- func FilterRequestsProtectedKind(f nostr.Filter) bool
- func GetAuthedPubkey(client nostr.ClientInterface) string
- func GetChallengeForConnection(client nostr.ClientInterface) string
- func HandleAuth(client nostr.ClientInterface, message []interface{})
- func HandleClose(client nostr.ClientInterface, message []interface{})
- func HandleCount(client nostr.ClientInterface, message []interface{})
- func HandleEvent(client nostr.ClientInterface, message []interface{})
- func HandleReq(client nostr.ClientInterface, message []interface{})
- func IsAuthenticated(client nostr.ClientInterface) bool
- func SetAuthenticated(client nostr.ClientInterface, pubkey string)
- func SetChallengeForConnection(client nostr.ClientInterface, challenge string)
- func VerifyAuthEvent(client nostr.ClientInterface, evt nostr.Event) error
- func VerifyNIP98Event(evt nostr.Event, method, absURL, bodyHashHex string) error
Constants ¶
const NIP98AuthKind = 27235
NIP98AuthKind is the event kind reserved by NIP-98 for HTTP Auth.
Variables ¶
var OnEventStored func(evt nostr.Event)
OnEventStored is called after an event is successfully stored. Set by the server package to broadcast events to active subscribers.
Functions ¶
func CanServeProtectedEvent ¶ added in v0.7.0
CanServeProtectedEvent reports whether evt may be served to a client that has AUTHed as authedPubkey ("" if unauthenticated). Non-protected events always pass; a protected event passes only when the authed pubkey appears in one of its p tags.
func CleanupClient ¶ added in v0.7.1
func CleanupClient(client nostr.ClientInterface)
CleanupClient releases all per-connection auth state for a client that has disconnected. Both `challenges` and `authSessions` are keyed by the client pointer, so failing to delete here pins the entire client object graph (subscriptions, filter slices, the outbound channel, the rate limiter) in memory for the life of the process — see #92.
The `challenges` entry in particular leaks for EVERY connection, since one is set unconditionally on connect (SetChallengeForConnection) but only cleared on a successful AUTH — which most public-relay connections never do.
Must be called once per connection on teardown. The canonical caller is the clientReader defer in server/client.go, which is the cleanup path that runs for every disconnect. Idempotent: deleting a missing key is a no-op, so a redundant call is harmless.
func ClearChallengeForConnection ¶ added in v0.5.0
func ClearChallengeForConnection(client nostr.ClientInterface)
ClearChallengeForConnection removes the challenge for a connection
func FilterRequestsProtectedKind ¶ added in v0.7.0
FilterRequestsProtectedKind reports whether the filter explicitly asks for a protected kind. Used to decide when an unauthenticated REQ/COUNT should be told to AUTH (vs. a broad filter where we just silently omit the events).
func GetAuthedPubkey ¶ added in v0.6.0
func GetAuthedPubkey(client nostr.ClientInterface) string
GetAuthedPubkey returns the pubkey the connection authenticated as, or "" if the connection has not completed NIP-42 AUTH.
func GetChallengeForConnection ¶
func GetChallengeForConnection(client nostr.ClientInterface) string
GetChallengeForConnection retrieves the challenge string for a given connection
func HandleAuth ¶
func HandleAuth(client nostr.ClientInterface, message []interface{})
HandleAuth processes the "AUTH" message type as defined in NIP-42
func HandleClose ¶
func HandleClose(client nostr.ClientInterface, message []interface{})
HandleClose processes a "CLOSE" message from a client
func HandleCount ¶ added in v0.6.0
func HandleCount(client nostr.ClientInterface, message []interface{})
HandleCount processes a NIP-45 "COUNT" message. The wire format mirrors REQ — `["COUNT", <sub_id>, <filter1>, ...]` — and the response is `["COUNT", <sub_id>, {"count": N}]` (with an optional `approximate: true` field).
Filter parsing intentionally duplicates the REQ-side logic rather than sharing it: REQ also creates a long-lived subscription; COUNT is a one-shot read. The shared bits are small enough that a helper would obscure more than it saves.
func HandleEvent ¶
func HandleEvent(client nostr.ClientInterface, message []interface{})
HandleEvent processes an "EVENT" message
func HandleReq ¶
func HandleReq(client nostr.ClientInterface, message []interface{})
HandleReq processes a new subscription request with proper subscription management
func IsAuthenticated ¶
func IsAuthenticated(client nostr.ClientInterface) bool
IsAuthenticated checks if a connection is authenticated.
func SetAuthenticated ¶
func SetAuthenticated(client nostr.ClientInterface, pubkey string)
SetAuthenticated marks a connection as authenticated and records the authenticated pubkey.
func SetChallengeForConnection ¶
func SetChallengeForConnection(client nostr.ClientInterface, challenge string)
SetChallengeForConnection sets the challenge string for a given connection
func VerifyAuthEvent ¶
func VerifyAuthEvent(client nostr.ClientInterface, evt nostr.Event) error
VerifyAuthEvent verifies the authentication event according to NIP-42
func VerifyNIP98Event ¶ added in v0.7.0
VerifyNIP98Event verifies an HTTP Auth event per NIP-98.
Callers (typically the HTTP middleware in server/api/authHelpers.go) supply the request context the event must commit to:
- method: the uppercase HTTP method of the request
- absURL: the absolute URL of the request as the server sees it, reconstructed honoring X-Forwarded-Proto / X-Forwarded-Host so the value matches what the client signed
- bodyHashHex: sha256 hex digest of the request body. Pass "" for methods/requests with no body — in that case the event's payload tag (if any) must also be empty/absent
On success the caller may trust evt.PubKey as the request's authenticated identity. NIP-98 does not standardize a relay-side challenge/nonce; the tight created_at window is the only replay defense.
Types ¶
This section is empty.