package auth import ( "context" "crypto/sha256" "encoding/base64" "encoding/json" "fmt" "time" "northwest.io/nostr" ) // NostrCredentials implements credentials.PerRPCCredentials for NIP-98 auth. type NostrCredentials struct { key *nostr.Key includePayload bool } func NewNostrCredentials(key *nostr.Key) *NostrCredentials { return &NostrCredentials{ key: key, includePayload: false, } } func NewNostrCredentialsWithPayload(key *nostr.Key) *NostrCredentials { return &NostrCredentials{ key: key, includePayload: true, } } func (n *NostrCredentials) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { if len(uri) == 0 { return nil, fmt.Errorf("no URI provided") } event := &nostr.Event{ PubKey: n.key.Public(), CreatedAt: time.Now().Unix(), Kind: 27235, Tags: nostr.Tags{}, Content: "", } event.Tags = append(event.Tags, nostr.Tag{"u", uri[0]}) event.Tags = append(event.Tags, nostr.Tag{"method", "POST"}) if err := n.key.Sign(event); err != nil { return nil, fmt.Errorf("failed to sign auth event: %w", err) } eventJSON, err := json.Marshal(event) if err != nil { return nil, fmt.Errorf("failed to marshal auth event: %w", err) } authHeader := "Nostr " + base64.StdEncoding.EncodeToString(eventJSON) return map[string]string{ "authorization": authHeader, }, nil } func (n *NostrCredentials) RequireTransportSecurity() bool { return false } type NostrCredentialsWithTLS struct { *NostrCredentials } func NewNostrCredentialsWithTLS(key *nostr.Key) *NostrCredentialsWithTLS { return &NostrCredentialsWithTLS{ NostrCredentials: NewNostrCredentials(key), } } func (n *NostrCredentialsWithTLS) RequireTransportSecurity() bool { return true } func HashPayload(payload []byte) string { hash := sha256.Sum256(payload) return fmt.Sprintf("%x", hash) }