docstrings for many functions.

This commit is contained in:
fiatjaf
2025-03-04 11:08:31 -03:00
parent a82780e82e
commit 5bfaed2740
22 changed files with 293 additions and 66 deletions

View File

@@ -9,15 +9,20 @@ import (
"github.com/nbd-wtf/go-nostr/nip46"
)
// BunkerSigner is a signer that asks a bunker using NIP-46 every time it needs to do an operation.
// BunkerSigner is a signer that delegates operations to a remote bunker using NIP-46.
// It communicates with the bunker for all cryptographic operations rather than
// handling the private key locally.
type BunkerSigner struct {
bunker *nip46.BunkerClient
}
// NewBunkerSignerFromBunkerClient creates a new BunkerSigner from an existing BunkerClient.
func NewBunkerSignerFromBunkerClient(bc *nip46.BunkerClient) BunkerSigner {
return BunkerSigner{bc}
}
// GetPublicKey retrieves the public key from the remote bunker.
// It uses a timeout to prevent hanging indefinitely.
func (bs BunkerSigner) GetPublicKey(ctx context.Context) (string, error) {
ctx, cancel := context.WithTimeoutCause(ctx, time.Second*30, errors.New("get_public_key took too long"))
defer cancel()
@@ -28,16 +33,20 @@ func (bs BunkerSigner) GetPublicKey(ctx context.Context) (string, error) {
return pk, nil
}
// SignEvent sends the event to the remote bunker for signing.
// It uses a timeout to prevent hanging indefinitely.
func (bs BunkerSigner) SignEvent(ctx context.Context, evt *nostr.Event) error {
ctx, cancel := context.WithTimeoutCause(ctx, time.Second*30, errors.New("sign_event took too long"))
defer cancel()
return bs.bunker.SignEvent(ctx, evt)
}
// Encrypt encrypts a plaintext message for a recipient using the remote bunker.
func (bs BunkerSigner) Encrypt(ctx context.Context, plaintext string, recipient string) (string, error) {
return bs.bunker.NIP44Encrypt(ctx, recipient, plaintext)
}
// Decrypt decrypts a base64-encoded ciphertext from a sender using the remote bunker.
func (bs BunkerSigner) Decrypt(ctx context.Context, base64ciphertext string, sender string) (plaintext string, err error) {
return bs.bunker.NIP44Encrypt(ctx, sender, base64ciphertext)
}

View File

@@ -9,13 +9,18 @@ import (
"github.com/nbd-wtf/go-nostr/nip49"
)
// EncryptedKeySigner is a signer that must always ask the user for a password before every operation.
// EncryptedKeySigner is a signer that must ask the user for a password before every operation.
// It stores the private key in encrypted form (NIP-49) and uses a callback to request the password
// when needed for operations.
type EncryptedKeySigner struct {
ncryptsec string
pk string
callback func(context.Context) string
}
// GetPublicKey returns the public key associated with this signer.
// If the public key is not cached, it will decrypt the private key using the password
// callback to derive the public key.
func (es *EncryptedKeySigner) GetPublicKey(ctx context.Context) (string, error) {
if es.pk != "" {
return es.pk, nil
@@ -33,6 +38,8 @@ func (es *EncryptedKeySigner) GetPublicKey(ctx context.Context) (string, error)
return pk, nil
}
// SignEvent signs the provided event by first decrypting the private key
// using the password callback, then signing the event with the decrypted key.
func (es *EncryptedKeySigner) SignEvent(ctx context.Context, evt *nostr.Event) error {
password := es.callback(ctx)
sk, err := nip49.Decrypt(es.ncryptsec, password)
@@ -43,6 +50,8 @@ func (es *EncryptedKeySigner) SignEvent(ctx context.Context, evt *nostr.Event) e
return evt.Sign(sk)
}
// Encrypt encrypts a plaintext message for a recipient using NIP-44.
// It first decrypts the private key using the password callback.
func (es EncryptedKeySigner) Encrypt(ctx context.Context, plaintext string, recipient string) (c64 string, err error) {
password := es.callback(ctx)
sk, err := nip49.Decrypt(es.ncryptsec, password)
@@ -56,6 +65,8 @@ func (es EncryptedKeySigner) Encrypt(ctx context.Context, plaintext string, reci
return nip44.Encrypt(plaintext, ck)
}
// Decrypt decrypts a base64-encoded ciphertext from a sender using NIP-44.
// It first decrypts the private key using the password callback.
func (es EncryptedKeySigner) Decrypt(ctx context.Context, base64ciphertext string, sender string) (plaintext string, err error) {
password := es.callback(ctx)
sk, err := nip49.Decrypt(es.ncryptsec, password)

View File

@@ -22,19 +22,37 @@ var (
_ nostr.Keyer = (*ManualSigner)(nil)
)
// SignerOptions contains configuration options for creating a new signer.
type SignerOptions struct {
// BunkerClientSecretKey is the secret key used for the bunker client
BunkerClientSecretKey string
BunkerSignTimeout time.Duration
BunkerAuthHandler func(string)
// if a PasswordHandler is provided the key will be stored encrypted and this function will be called
// BunkerSignTimeout is the timeout duration for bunker signing operations
BunkerSignTimeout time.Duration
// BunkerAuthHandler is called when authentication is needed for bunker operations
BunkerAuthHandler func(string)
// PasswordHandler is called when an operation needs access to the encrypted key.
// If provided, the key will be stored encrypted and this function will be called
// every time an operation needs access to the key so the user can be prompted.
PasswordHandler func(context.Context) string
// if instead a Password is provided along with a ncryptsec, then the key will be decrypted and stored in plaintext.
// Password is used along with ncryptsec to decrypt the key.
// If provided, the key will be decrypted and stored in plaintext.
Password string
}
// New creates a new Keyer implementation based on the input string format.
// It supports various input formats:
// - ncryptsec: Creates an EncryptedKeySigner or KeySigner depending on options
// - NIP-46 bunker URL or NIP-05 identifier: Creates a BunkerSigner
// - nsec: Creates a KeySigner
// - hex private key: Creates a KeySigner
//
// The context is used for operations that may require network access.
// The pool is used for relay connections when needed.
// Options are used for additional pieces required for EncryptedKeySigner and BunkerSigner.
func New(ctx context.Context, pool *nostr.SimplePool, input string, opts *SignerOptions) (nostr.Keyer, error) {
if opts == nil {
opts = &SignerOptions{}

View File

@@ -6,28 +6,40 @@ import (
"github.com/nbd-wtf/go-nostr"
)
// ManualSigner is a signer that doesn't really do anything, it just calls the functions given to it.
// It can be used when an app for some reason wants to ask the user to manually provide a signed event
// by copy-and-paste, for example.
// ManualSigner is a signer that delegates all operations to user-provided functions.
// It can be used when an app wants to ask the user or some custom server to manually provide a
// signed event or an encrypted or decrypted payload by copy-and-paste, for example, or when the
// app wants to implement custom signing logic.
type ManualSigner struct {
// ManualGetPublicKey is called when the public key is needed
ManualGetPublicKey func(context.Context) (string, error)
ManualSignEvent func(context.Context, *nostr.Event) error
ManualEncrypt func(ctx context.Context, plaintext string, recipientPublicKey string) (base64ciphertext string, err error)
ManualDecrypt func(ctx context.Context, base64ciphertext string, senderPublicKey string) (plaintext string, err error)
// ManualSignEvent is called when an event needs to be signed
ManualSignEvent func(context.Context, *nostr.Event) error
// ManualEncrypt is called when a message needs to be encrypted
ManualEncrypt func(ctx context.Context, plaintext string, recipientPublicKey string) (base64ciphertext string, err error)
// ManualDecrypt is called when a message needs to be decrypted
ManualDecrypt func(ctx context.Context, base64ciphertext string, senderPublicKey string) (plaintext string, err error)
}
// SignEvent delegates event signing to the ManualSignEvent function.
func (ms ManualSigner) SignEvent(ctx context.Context, evt *nostr.Event) error {
return ms.ManualSignEvent(ctx, evt)
}
// GetPublicKey delegates public key retrieval to the ManualGetPublicKey function.
func (ms ManualSigner) GetPublicKey(ctx context.Context) (string, error) {
return ms.ManualGetPublicKey(ctx)
}
// Encrypt delegates encryption to the ManualEncrypt function.
func (ms ManualSigner) Encrypt(ctx context.Context, plaintext string, recipient string) (c64 string, err error) {
return ms.ManualEncrypt(ctx, plaintext, recipient)
}
// Decrypt delegates decryption to the ManualDecrypt function.
func (ms ManualSigner) Decrypt(ctx context.Context, base64ciphertext string, sender string) (plaintext string, err error) {
return ms.ManualDecrypt(ctx, base64ciphertext, sender)
}

View File

@@ -8,7 +8,8 @@ import (
"github.com/puzpuzpuz/xsync/v3"
)
// Keysigner is a signer that holds the private key in memory and can do all the operations instantly and easily.
// KeySigner is a signer that holds the private key in memory and can perform
// all operations instantly and easily.
type KeySigner struct {
sk string
pk string
@@ -16,6 +17,8 @@ type KeySigner struct {
conversationKeys *xsync.MapOf[string, [32]byte]
}
// NewPlainKeySigner creates a new KeySigner from a private key.
// Returns an error if the private key is invalid.
func NewPlainKeySigner(sec string) (KeySigner, error) {
pk, err := nostr.GetPublicKey(sec)
if err != nil {
@@ -24,9 +27,15 @@ func NewPlainKeySigner(sec string) (KeySigner, error) {
return KeySigner{sec, pk, xsync.NewMapOf[string, [32]byte]()}, nil
}
// SignEvent signs the provided event with the signer's private key.
// It sets the event's ID, PubKey, and Sig fields.
func (ks KeySigner) SignEvent(ctx context.Context, evt *nostr.Event) error { return evt.Sign(ks.sk) }
// GetPublicKey returns the public key associated with this signer.
func (ks KeySigner) GetPublicKey(ctx context.Context) (string, error) { return ks.pk, nil }
// Encrypt encrypts a plaintext message for a recipient using NIP-44.
// It caches conversation keys for efficiency in repeated operations.
func (ks KeySigner) Encrypt(ctx context.Context, plaintext string, recipient string) (string, error) {
ck, ok := ks.conversationKeys.Load(recipient)
if !ok {
@@ -40,6 +49,8 @@ func (ks KeySigner) Encrypt(ctx context.Context, plaintext string, recipient str
return nip44.Encrypt(plaintext, ck)
}
// Decrypt decrypts a base64-encoded ciphertext from a sender using NIP-44.
// It caches conversation keys for efficiency in repeated operations.
func (ks KeySigner) Decrypt(ctx context.Context, base64ciphertext string, sender string) (string, error) {
ck, ok := ks.conversationKeys.Load(sender)
if !ok {