identity.go raw

   1  //go:build !(js && wasm)
   2  
   3  package database
   4  
   5  import (
   6  	"errors"
   7  	"fmt"
   8  
   9  	"github.com/dgraph-io/badger/v4"
  10  	"next.orly.dev/pkg/lol/chk"
  11  	"next.orly.dev/pkg/lol/log"
  12  	"next.orly.dev/pkg/nostr/crypto/keys"
  13  	"next.orly.dev/pkg/nostr/encoders/hex"
  14  )
  15  
  16  const relayIdentitySecretKey = "relay:identity:sk"
  17  
  18  // GetRelayIdentitySecret returns the relay identity secret key bytes if present.
  19  // If the key is not found, returns (nil, badger.ErrKeyNotFound).
  20  func (d *D) GetRelayIdentitySecret() (skb []byte, err error) {
  21  	err = d.DB.View(func(txn *badger.Txn) error {
  22  		item, err := txn.Get([]byte(relayIdentitySecretKey))
  23  		if errors.Is(err, badger.ErrKeyNotFound) {
  24  			return err
  25  		}
  26  		if err != nil {
  27  			return err
  28  		}
  29  		return item.Value(func(val []byte) error {
  30  			// value stored as hex string
  31  			b, err := hex.Dec(string(val))
  32  			if err != nil {
  33  				return err
  34  			}
  35  			skb = make([]byte, len(b))
  36  			copy(skb, b)
  37  			return nil
  38  		})
  39  	})
  40  	return
  41  }
  42  
  43  // SetRelayIdentitySecret stores the relay identity secret key bytes (expects 32 bytes).
  44  func (d *D) SetRelayIdentitySecret(skb []byte) (err error) {
  45  	if len(skb) != 32 {
  46  		return fmt.Errorf("invalid secret key length: %d", len(skb))
  47  	}
  48  	val := []byte(hex.Enc(skb))
  49  	return d.DB.Update(func(txn *badger.Txn) error {
  50  		return txn.Set([]byte(relayIdentitySecretKey), val)
  51  	})
  52  }
  53  
  54  // GetOrCreateRelayIdentitySecret retrieves the existing relay identity secret
  55  // key or creates and stores a new one if none exists.
  56  func (d *D) GetOrCreateRelayIdentitySecret() (skb []byte, err error) {
  57  	// Try get fast path
  58  	if skb, err = d.GetRelayIdentitySecret(); err == nil && len(skb) == 32 {
  59  		return skb, nil
  60  	}
  61  	if err != nil && !errors.Is(err, badger.ErrKeyNotFound) {
  62  		return nil, err
  63  	}
  64  
  65  	// Create new key and store atomically
  66  	var gen []byte
  67  	if gen, err = keys.GenerateSecretKey(); chk.E(err) {
  68  		return nil, err
  69  	}
  70  	if err = d.SetRelayIdentitySecret(gen); chk.E(err) {
  71  		return nil, err
  72  	}
  73  	log.I.F("generated new relay identity key (pub=%s)", mustPub(gen))
  74  	return gen, nil
  75  }
  76  
  77  func mustPub(skb []byte) string {
  78  	pk, err := keys.SecretBytesToPubKeyHex(skb)
  79  	if err != nil {
  80  		return ""
  81  	}
  82  	return pk
  83  }
  84