auth.go raw

   1  package main
   2  
   3  import (
   4  	"encoding/hex"
   5  	"net/http"
   6  	"strings"
   7  
   8  	"next.orly.dev/pkg/nostr/httpauth"
   9  	"next.orly.dev/pkg/lol/chk"
  10  )
  11  
  12  // AuthMiddleware provides NIP-98 authentication for the admin API.
  13  type AuthMiddleware struct {
  14  	owners map[string]struct{}
  15  }
  16  
  17  // NewAuthMiddleware creates a new auth middleware with the given owner pubkeys.
  18  func NewAuthMiddleware(owners []string) *AuthMiddleware {
  19  	ownerMap := make(map[string]struct{}, len(owners))
  20  	for _, o := range owners {
  21  		// Normalize to lowercase hex
  22  		ownerMap[strings.ToLower(o)] = struct{}{}
  23  	}
  24  	return &AuthMiddleware{owners: ownerMap}
  25  }
  26  
  27  // RequireAuth wraps a handler to require NIP-98 authentication from an owner.
  28  func (a *AuthMiddleware) RequireAuth(next http.HandlerFunc) http.HandlerFunc {
  29  	return func(w http.ResponseWriter, r *http.Request) {
  30  		// Validate NIP-98 authentication
  31  		valid, pubkeyBytes, err := httpauth.CheckAuth(r)
  32  		if chk.E(err) || !valid {
  33  			errorMsg := "NIP-98 authentication required"
  34  			if err != nil {
  35  				errorMsg = err.Error()
  36  			}
  37  			http.Error(w, errorMsg, http.StatusUnauthorized)
  38  			return
  39  		}
  40  
  41  		// Convert pubkey bytes to hex string
  42  		pubkeyHex := hex.EncodeToString(pubkeyBytes)
  43  
  44  		// Check if pubkey is in owners list
  45  		if !a.IsOwner(pubkeyHex) {
  46  			http.Error(w, "Not authorized - owner access required", http.StatusForbidden)
  47  			return
  48  		}
  49  
  50  		// Authentication successful, call the next handler
  51  		next(w, r)
  52  	}
  53  }
  54  
  55  // IsOwner checks if the given pubkey is in the owners list.
  56  func (a *AuthMiddleware) IsOwner(pubkey string) bool {
  57  	if len(a.owners) == 0 {
  58  		// No owners configured - deny all access
  59  		return false
  60  	}
  61  	_, ok := a.owners[strings.ToLower(pubkey)]
  62  	return ok
  63  }
  64  
  65  // AddOwner adds a pubkey to the owners list.
  66  func (a *AuthMiddleware) AddOwner(pubkey string) {
  67  	a.owners[strings.ToLower(pubkey)] = struct{}{}
  68  }
  69  
  70  // RemoveOwner removes a pubkey from the owners list.
  71  func (a *AuthMiddleware) RemoveOwner(pubkey string) {
  72  	delete(a.owners, strings.ToLower(pubkey))
  73  }
  74  
  75  // Owners returns the list of owner pubkeys.
  76  func (a *AuthMiddleware) Owners() []string {
  77  	owners := make([]string, 0, len(a.owners))
  78  	for o := range a.owners {
  79  		owners = append(owners, o)
  80  	}
  81  	return owners
  82  }
  83