From 4fc493e6d8cc20137f920f8647e39fc5051bb245 Mon Sep 17 00:00:00 2001 From: bndw Date: Sat, 14 Feb 2026 12:03:21 -0800 Subject: refactor: remove frivolous comments from auth validation/credentials Also removed internal/nostr package - now using northwest.io/nostr library. --- internal/auth/auth_test.go | 2 +- internal/auth/credentials.go | 35 +++-------------------------------- internal/auth/validation.go | 33 +++++---------------------------- 3 files changed, 9 insertions(+), 61 deletions(-) (limited to 'internal/auth') diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go index bcbb4a3..7b0fa13 100644 --- a/internal/auth/auth_test.go +++ b/internal/auth/auth_test.go @@ -8,7 +8,7 @@ import ( "time" "google.golang.org/grpc/metadata" - "northwest.io/muxstr/internal/nostr" + "northwest.io/nostr" ) func TestNostrCredentials(t *testing.T) { diff --git a/internal/auth/credentials.go b/internal/auth/credentials.go index c558653..8e8aae8 100644 --- a/internal/auth/credentials.go +++ b/internal/auth/credentials.go @@ -8,20 +8,15 @@ import ( "fmt" "time" - "northwest.io/muxstr/internal/nostr" + "northwest.io/nostr" ) -// NostrCredentials implements credentials.PerRPCCredentials for NIP-98 authentication. -// It automatically signs each gRPC request with a Nostr event (kind 27235) and -// attaches it to the Authorization header. +// NostrCredentials implements credentials.PerRPCCredentials for NIP-98 auth. type NostrCredentials struct { key *nostr.Key includePayload bool } -// NewNostrCredentials creates credentials using the provided key. -// Each RPC call will be authenticated with a freshly signed NIP-98 event. -// The key must have a private key (CanSign() must return true). func NewNostrCredentials(key *nostr.Key) *NostrCredentials { return &NostrCredentials{ key: key, @@ -29,8 +24,6 @@ func NewNostrCredentials(key *nostr.Key) *NostrCredentials { } } -// NewNostrCredentialsWithPayload creates credentials that include payload hashes. -// When enabled, a SHA256 hash of the request body is included in the auth event. func NewNostrCredentialsWithPayload(key *nostr.Key) *NostrCredentials { return &NostrCredentials{ key: key, @@ -38,39 +31,26 @@ func NewNostrCredentialsWithPayload(key *nostr.Key) *NostrCredentials { } } -// GetRequestMetadata implements credentials.PerRPCCredentials. -// It creates and signs a NIP-98 auth event for each request. func (n *NostrCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { if len(uri) == 0 { return nil, fmt.Errorf("no URI provided") } - // Create kind 27235 event (NIP-98 HTTP Auth) event := &nostr.Event{ PubKey: n.key.Public(), CreatedAt: time.Now().Unix(), - Kind: 27235, // NIP-98 HTTP Auth + Kind: 27235, Tags: nostr.Tags{}, Content: "", } - // Add URL tag event.Tags = append(event.Tags, nostr.Tag{"u", uri[0]}) - - // Add method tag - default to POST for gRPC - // The URI contains the method name, e.g., /nostr.v1.NostrRelay/PublishEvent event.Tags = append(event.Tags, nostr.Tag{"method", "POST"}) - // TODO: Add payload hash if includePayload is true - // This requires access to the request body, which isn't available in GetRequestMetadata - // We could use a context key to pass the payload hash from the application - - // Sign the event if err := n.key.Sign(event); err != nil { return nil, fmt.Errorf("failed to sign auth event: %w", err) } - // Encode event as base64 JSON eventJSON, err := json.Marshal(event) if err != nil { return nil, fmt.Errorf("failed to marshal auth event: %w", err) @@ -83,33 +63,24 @@ func (n *NostrCredentials) GetRequestMetadata(ctx context.Context, uri ...string }, nil } -// RequireTransportSecurity implements credentials.PerRPCCredentials. -// Returns false to allow usage over insecure connections (for development). -// In production, use TLS and set this to true. func (n *NostrCredentials) RequireTransportSecurity() bool { return false } -// SetRequireTLS configures whether TLS is required. -// When true, the credentials will only work over TLS connections. type NostrCredentialsWithTLS struct { *NostrCredentials } -// NewNostrCredentialsWithTLS creates credentials that require TLS. func NewNostrCredentialsWithTLS(key *nostr.Key) *NostrCredentialsWithTLS { return &NostrCredentialsWithTLS{ NostrCredentials: NewNostrCredentials(key), } } -// RequireTransportSecurity returns true to enforce TLS. func (n *NostrCredentialsWithTLS) RequireTransportSecurity() bool { return true } -// HashPayload creates a SHA256 hash of the payload for inclusion in auth events. -// This can be used to verify request integrity. func HashPayload(payload []byte) string { hash := sha256.Sum256(payload) return fmt.Sprintf("%x", hash) diff --git a/internal/auth/validation.go b/internal/auth/validation.go index 11435ee..8b9d8a1 100644 --- a/internal/auth/validation.go +++ b/internal/auth/validation.go @@ -7,52 +7,37 @@ import ( "strings" "time" - "northwest.io/muxstr/internal/nostr" + "northwest.io/nostr" ) -// ValidationOptions configures how NIP-98 events are validated. type ValidationOptions struct { - // TimestampWindow is the maximum age of events in seconds TimestampWindow int64 - - // ValidatePayload checks the payload hash if present ValidatePayload bool - - // ExpectedURI is the URI that should match the 'u' tag - ExpectedURI string - - // ExpectedMethod is the method that should match the 'method' tag - ExpectedMethod string - - // PayloadHash is the expected payload hash (if ValidatePayload is true) - PayloadHash string + ExpectedURI string + ExpectedMethod string + PayloadHash string } -// ParseAuthHeader extracts and decodes a NIP-98 event from an Authorization header. -// Expected format: "Nostr " +// ParseAuthHeader parses "Nostr " format. func ParseAuthHeader(header string) (*nostr.Event, error) { if header == "" { return nil, fmt.Errorf("empty authorization header") } - // Check for "Nostr " prefix if !strings.HasPrefix(header, "Nostr ") { return nil, fmt.Errorf("invalid authorization header: must start with 'Nostr '") } - // Extract base64 part encoded := strings.TrimPrefix(header, "Nostr ") if encoded == "" { return nil, fmt.Errorf("empty authorization token") } - // Decode base64 decoded, err := base64.StdEncoding.DecodeString(encoded) if err != nil { return nil, fmt.Errorf("invalid base64 encoding: %w", err) } - // Unmarshal event var event nostr.Event if err := json.Unmarshal(decoded, &event); err != nil { return nil, fmt.Errorf("invalid event JSON: %w", err) @@ -61,19 +46,15 @@ func ParseAuthHeader(header string) (*nostr.Event, error) { return &event, nil } -// ValidateAuthEvent validates a NIP-98 auth event according to the spec. func ValidateAuthEvent(event *nostr.Event, opts ValidationOptions) error { - // Check event kind if event.Kind != 27235 { return fmt.Errorf("invalid event kind: expected 27235, got %d", event.Kind) } - // Verify signature if !event.Verify() { return fmt.Errorf("invalid event signature") } - // Check timestamp (prevent replay attacks) now := time.Now().Unix() age := now - event.CreatedAt @@ -85,7 +66,6 @@ func ValidateAuthEvent(event *nostr.Event, opts ValidationOptions) error { return fmt.Errorf("event too old: %d seconds (max %d)", age, opts.TimestampWindow) } - // Validate 'u' tag (URL) if opts.ExpectedURI != "" { uTag := event.Tags.Find("u") if uTag == nil { @@ -98,7 +78,6 @@ func ValidateAuthEvent(event *nostr.Event, opts ValidationOptions) error { } } - // Validate 'method' tag if opts.ExpectedMethod != "" { methodTag := event.Tags.Find("method") if methodTag == nil { @@ -111,7 +90,6 @@ func ValidateAuthEvent(event *nostr.Event, opts ValidationOptions) error { } } - // Validate payload hash if requested if opts.ValidatePayload && opts.PayloadHash != "" { payloadTag := event.Tags.Find("payload") if payloadTag == nil { @@ -127,7 +105,6 @@ func ValidateAuthEvent(event *nostr.Event, opts ValidationOptions) error { return nil } -// ExtractPubkey returns the pubkey from a validated auth event. func ExtractPubkey(event *nostr.Event) string { return event.PubKey } -- cgit v1.2.3