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