nip98auth.go raw

   1  package httpauth
   2  
   3  import (
   4  	"encoding/base64"
   5  	"net/http"
   6  	"net/url"
   7  	"strings"
   8  
   9  	"next.orly.dev/pkg/nostr/encoders/event"
  10  	"next.orly.dev/pkg/nostr/encoders/kind"
  11  	"next.orly.dev/pkg/nostr/encoders/tag"
  12  	"next.orly.dev/pkg/nostr/encoders/timestamp"
  13  	"next.orly.dev/pkg/nostr/interfaces/signer"
  14  	"next.orly.dev/pkg/lol/chk"
  15  )
  16  
  17  const (
  18  	HeaderKey   = "Authorization"
  19  	NIP98Prefix = "Nostr"
  20  )
  21  
  22  // MakeNIP98Event creates a new NIP-98 event. If expiry is given, method is
  23  // ignored; otherwise either option is the same.
  24  func MakeNIP98Event(u, method, hash string, expiry int64) (ev *event.E) {
  25  	var t []*tag.T
  26  	t = append(t, tag.NewFromAny("u", u))
  27  	if expiry > 0 {
  28  		t = append(
  29  			t,
  30  			tag.NewFromAny("expiration", timestamp.FromUnix(expiry).String()),
  31  		)
  32  	} else {
  33  		t = append(
  34  			t,
  35  			tag.NewFromAny("method", strings.ToUpper(method)),
  36  		)
  37  	}
  38  	if hash != "" {
  39  		t = append(t, tag.NewFromAny("payload", hash))
  40  	}
  41  	ev = &event.E{
  42  		CreatedAt: timestamp.Now().V,
  43  		Kind:      kind.HTTPAuth.K,
  44  		Tags:      tag.NewS(t...),
  45  	}
  46  	return
  47  }
  48  
  49  func CreateNIP98Blob(
  50  	ur, method, hash string, expiry int64, sign signer.I,
  51  ) (blob string, err error) {
  52  	ev := MakeNIP98Event(ur, method, hash, expiry)
  53  	if err = ev.Sign(sign); chk.E(err) {
  54  		return
  55  	}
  56  	// log.T.F("nip-98 http auth event:\n%s\n", ev.SerializeIndented())
  57  	blob = base64.URLEncoding.EncodeToString(ev.Serialize())
  58  	return
  59  }
  60  
  61  // AddNIP98Header creates a NIP-98 http auth event and adds the standard header to a provided
  62  // http.Request.
  63  func AddNIP98Header(
  64  	r *http.Request, ur *url.URL, method, hash string,
  65  	sign signer.I, expiry int64,
  66  ) (err error) {
  67  	var b64 string
  68  	if b64, err = CreateNIP98Blob(
  69  		ur.String(), method, hash, expiry, sign,
  70  	); chk.E(err) {
  71  		return
  72  	}
  73  	r.Header.Add(HeaderKey, "Nostr "+b64)
  74  	return
  75  }
  76