mirror of
https://github.com/asmogo/nws.git
synced 2025-02-23 13:29:00 +00:00
linted stuff in exit package
This commit is contained in:
parent
59ff5034f9
commit
a8d3de5a93
45
exit/exit.go
45
exit/exit.go
@ -23,7 +23,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
startingReverseProxyMessage = "starting exit node with https reverse proxy"
|
startingReverseProxyMessage = "starting exit node with https reverse proxy"
|
||||||
generateKeyMessage = "Generated new private key. Please set your environment using the new key, otherwise your key will be lost."
|
generateKeyMessage = "Generated new private key. Please set your environment using the new key, otherwise your key will be lost." //nolint: lll
|
||||||
)
|
)
|
||||||
|
|
||||||
// Exit represents a structure that holds information related to an exit node.
|
// Exit represents a structure that holds information related to an exit node.
|
||||||
@ -43,7 +43,7 @@ type Exit struct {
|
|||||||
// It is used to establish and maintain connections between the Exit node and the backend host.
|
// It is used to establish and maintain connections between the Exit node and the backend host.
|
||||||
nostrConnectionMap *xsync.MapOf[string, *netstr.NostrConnection]
|
nostrConnectionMap *xsync.MapOf[string, *netstr.NostrConnection]
|
||||||
|
|
||||||
// mutexMap is a field in the Exit struct that represents a map used for synchronizing access to resources based on a string key.
|
// mutexMap is a field in the Exit struct used for synchronizing access to resources based on a string key.
|
||||||
mutexMap *MutexMap
|
mutexMap *MutexMap
|
||||||
|
|
||||||
// incomingChannel represents a channel used to receive incoming events from relays.
|
// incomingChannel represents a channel used to receive incoming events from relays.
|
||||||
@ -87,26 +87,25 @@ func NewExit(ctx context.Context, exitNodeConfig *config.ExitConfig) *Exit {
|
|||||||
// start reverse proxy if https port is set
|
// start reverse proxy if https port is set
|
||||||
if exitNodeConfig.HttpsPort != 0 {
|
if exitNodeConfig.HttpsPort != 0 {
|
||||||
exitNodeConfig.BackendHost = fmt.Sprintf(":%d", exitNodeConfig.HttpsPort)
|
exitNodeConfig.BackendHost = fmt.Sprintf(":%d", exitNodeConfig.HttpsPort)
|
||||||
go func(cfg *config.ExitConfig) {
|
go func(ctx context.Context, cfg *config.ExitConfig) {
|
||||||
slog.Info(startingReverseProxyMessage, "port", cfg.HttpsPort)
|
slog.Info(startingReverseProxyMessage, "port", cfg.HttpsPort)
|
||||||
err := exit.StartReverseProxy(cfg.HttpsTarget, cfg.HttpsPort)
|
err := exit.StartReverseProxy(ctx, cfg.HttpsTarget, cfg.HttpsPort)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}(exitNodeConfig)
|
}(ctx, exitNodeConfig)
|
||||||
}
|
}
|
||||||
// set config
|
// set config
|
||||||
exit.config = exitNodeConfig
|
exit.config = exitNodeConfig
|
||||||
// add relays to the pool
|
// add relays to the pool
|
||||||
for _, relayUrl := range exitNodeConfig.NostrRelays {
|
for _, relayURL := range exitNodeConfig.NostrRelays {
|
||||||
relay, err := exit.pool.EnsureRelay(relayUrl)
|
relay, err := exit.pool.EnsureRelay(relayURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println(err)
|
slog.Error("failed to ensure relay", "url", relayURL, "error", err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
exit.relays = append(exit.relays, relay)
|
exit.relays = append(exit.relays, relay)
|
||||||
fmt.Printf("added relay connection to %s\n", relayUrl)
|
slog.Info("added relay connection", "url", relayURL) //nolint:forbidigo
|
||||||
|
|
||||||
}
|
}
|
||||||
domain, err := exit.getDomain()
|
domain, err := exit.getDomain()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -127,17 +126,18 @@ func NewExit(ctx context.Context, exitNodeConfig *config.ExitConfig) *Exit {
|
|||||||
|
|
||||||
// getDomain returns the domain string used by the Exit node for communication with the Nostr relays.
|
// getDomain returns the domain string used by the Exit node for communication with the Nostr relays.
|
||||||
// It concatenates the relay URLs using base32 encoding with no padding, separated by dots.
|
// It concatenates the relay URLs using base32 encoding with no padding, separated by dots.
|
||||||
// The resulting domain is then appended with the base32 encoded public key obtained using the configured Nostr private key.
|
// The domain is then appended with the base32 encoded public key obtained using the configured Nostr private key.
|
||||||
// The final domain string is converted to lowercase and returned.
|
// The final domain string is converted to lowercase and returned.
|
||||||
// If any errors occur during the process, they are returned along with an
|
// If any errors occur during the process, they are returned along with an
|
||||||
func (e *Exit) getDomain() (string, error) {
|
func (e *Exit) getDomain() (string, error) {
|
||||||
var domain string
|
var domain string
|
||||||
// first lets build the subdomains
|
// first lets build the subdomains
|
||||||
for _, relayUrl := range e.config.NostrRelays {
|
for _, relayURL := range e.config.NostrRelays {
|
||||||
if domain == "" {
|
if domain == "" {
|
||||||
domain = base32.HexEncoding.WithPadding(base32.NoPadding).EncodeToString([]byte(relayUrl))
|
domain = base32.HexEncoding.WithPadding(base32.NoPadding).EncodeToString([]byte(relayURL))
|
||||||
} else {
|
} else {
|
||||||
domain = fmt.Sprintf("%s.%s", domain, base32.HexEncoding.WithPadding(base32.NoPadding).EncodeToString([]byte(relayUrl)))
|
domain = fmt.Sprintf("%s.%s",
|
||||||
|
domain, base32.HexEncoding.WithPadding(base32.NoPadding).EncodeToString([]byte(relayURL)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// create base32 encoded public key
|
// create base32 encoded public key
|
||||||
@ -173,21 +173,20 @@ func GetPublicKeyBase32(sk string) (string, error) {
|
|||||||
// setSubscriptions sets up subscriptions for the Exit node to receive incoming events from the specified relays.
|
// setSubscriptions sets up subscriptions for the Exit node to receive incoming events from the specified relays.
|
||||||
// It first obtains the public key using the configured Nostr private key.
|
// It first obtains the public key using the configured Nostr private key.
|
||||||
// Then it calls the `handleSubscription` method to open a subscription to the relays with the specified filters.
|
// Then it calls the `handleSubscription` method to open a subscription to the relays with the specified filters.
|
||||||
// This method runs in a separate goroutine and continuously handles the incoming events by calling the `processMessage` method.
|
// This method runs in a separate goroutine and continuously handles the incoming events by calling `processMessage`
|
||||||
// If the context is canceled before the subscription is established, it returns the context error.
|
// If the context is canceled before the subscription is established, it returns the context error.
|
||||||
// If any errors occur during the process, they are returned.
|
// If any errors occur during the process, they are returned.
|
||||||
// This method should be called once when starting the Exit node.
|
// This method should be called once when starting the Exit node.
|
||||||
func (e *Exit) setSubscriptions(ctx context.Context) error {
|
func (e *Exit) setSubscriptions(ctx context.Context) error {
|
||||||
pubKey, err := nostr.GetPublicKey(e.config.NostrPrivateKey)
|
pubKey, err := nostr.GetPublicKey(e.config.NostrPrivateKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to get public key: %w", err)
|
||||||
}
|
}
|
||||||
now := nostr.Now()
|
now := nostr.Now()
|
||||||
if err = e.handleSubscription(ctx, pubKey, now); err != nil {
|
if err = e.handleSubscription(ctx, pubKey, now); err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to handle subscription: %w", err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleSubscription handles the subscription to incoming events from relays based on the provided filters.
|
// handleSubscription handles the subscription to incoming events from relays based on the provided filters.
|
||||||
@ -195,7 +194,8 @@ func (e *Exit) setSubscriptions(ctx context.Context) error {
|
|||||||
// It returns an error if there is any issue with the subscription.
|
// It returns an error if there is any issue with the subscription.
|
||||||
func (e *Exit) handleSubscription(ctx context.Context, pubKey string, since nostr.Timestamp) error {
|
func (e *Exit) handleSubscription(ctx context.Context, pubKey string, since nostr.Timestamp) error {
|
||||||
incomingEventChannel := e.pool.SubMany(ctx, e.config.NostrRelays, nostr.Filters{
|
incomingEventChannel := e.pool.SubMany(ctx, e.config.NostrRelays, nostr.Filters{
|
||||||
{Kinds: []int{protocol.KindEphemeralEvent},
|
{
|
||||||
|
Kinds: []int{protocol.KindEphemeralEvent},
|
||||||
Since: &since,
|
Since: &since,
|
||||||
Tags: nostr.TagMap{
|
Tags: nostr.TagMap{
|
||||||
"p": []string{pubKey},
|
"p": []string{pubKey},
|
||||||
@ -239,7 +239,7 @@ func (e *Exit) processMessage(ctx context.Context, msg nostr.IncomingEvent) {
|
|||||||
}
|
}
|
||||||
protocolMessage, err := protocol.UnmarshalJSON([]byte(decodedMessage))
|
protocolMessage, err := protocol.UnmarshalJSON([]byte(decodedMessage))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("could not unmarshal message")
|
slog.Error("could not unmarshal message", "error", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
destination, err := protocol.Parse(protocolMessage.Destination)
|
destination, err := protocol.Parse(protocolMessage.Destination)
|
||||||
@ -289,7 +289,10 @@ func (e *Exit) handleConnect(
|
|||||||
dst, err = net.Dial("tcp", protocolMessage.Destination)
|
dst, err = net.Dial("tcp", protocolMessage.Destination)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
slog.Error("could not connect to backend", "error", err)
|
slog.Error("could not connect to backend", "error", err)
|
||||||
connection.Close()
|
err = connection.Close()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("could not close connection", "error", err)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
154
exit/https.go
154
exit/https.go
@ -8,6 +8,7 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"math/big"
|
"math/big"
|
||||||
@ -22,90 +23,123 @@ import (
|
|||||||
"github.com/nbd-wtf/go-nostr/nip04"
|
"github.com/nbd-wtf/go-nostr/nip04"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (e *Exit) StartReverseProxy(httpTarget string, port int32) error {
|
const (
|
||||||
ctx := context.Background()
|
headerTimeout = 5 * time.Second
|
||||||
ev := e.pool.QuerySingle(ctx, e.config.NostrRelays, nostr.Filter{
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
errNoCertificateEvent = errors.New("failed to find encrypted direct message")
|
||||||
|
)
|
||||||
|
|
||||||
|
func (e *Exit) StartReverseProxy(ctx context.Context, httpTarget string, port int32) error {
|
||||||
|
incomingEvent := e.pool.QuerySingle(ctx, e.config.NostrRelays, nostr.Filter{
|
||||||
Authors: []string{e.publicKey},
|
Authors: []string{e.publicKey},
|
||||||
Kinds: []int{protocol.KindCertificateEvent},
|
Kinds: []int{protocol.KindCertificateEvent},
|
||||||
Tags: nostr.TagMap{"p": []string{e.publicKey}},
|
Tags: nostr.TagMap{"p": []string{e.publicKey}},
|
||||||
})
|
})
|
||||||
var cert tls.Certificate
|
var cert tls.Certificate
|
||||||
if ev == nil {
|
var err error
|
||||||
|
if incomingEvent == nil {
|
||||||
certificate, err := e.createAndStoreCertificateData(ctx)
|
certificate, err := e.createAndStoreCertificateData(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cert = *certificate
|
cert = *certificate
|
||||||
} else {
|
} else {
|
||||||
slog.Info("found certificate event", "certificate", ev.Content)
|
cert, err = e.handleCertificateEvent(incomingEvent, ctx, cert)
|
||||||
// load private key from file
|
|
||||||
privateKeyEvent := e.pool.QuerySingle(ctx, e.config.NostrRelays, nostr.Filter{
|
|
||||||
Authors: []string{e.publicKey},
|
|
||||||
Kinds: []int{protocol.KindPrivateKeyEvent},
|
|
||||||
Tags: nostr.TagMap{"p": []string{e.publicKey}},
|
|
||||||
})
|
|
||||||
if privateKeyEvent == nil {
|
|
||||||
return fmt.Errorf("failed to find encrypted direct message")
|
|
||||||
}
|
|
||||||
sharedKey, err := nip04.ComputeSharedSecret(privateKeyEvent.PubKey, e.config.NostrPrivateKey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
decodedMessage, err := nip04.Decrypt(privateKeyEvent.Content, sharedKey)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
message, err := protocol.UnmarshalJSON([]byte(decodedMessage))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
block, _ := pem.Decode(message.Data)
|
|
||||||
if block == nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "error: failed to decode PEM block containing private key\n")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got, want := block.Type, "RSA PRIVATE KEY"; got != want {
|
|
||||||
fmt.Fprintf(os.Stderr, "error: decoded PEM block of type %s, but wanted %s", got, want)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
certBlock, _ := pem.Decode([]byte(ev.Content))
|
|
||||||
if certBlock == nil {
|
|
||||||
fmt.Fprintf(os.Stderr, "Failed to parse certificate PEM.")
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
parsedCert, err := x509.ParseCertificate(certBlock.Bytes)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
cert = tls.Certificate{
|
|
||||||
Certificate: [][]byte{certBlock.Bytes},
|
|
||||||
PrivateKey: priv,
|
|
||||||
Leaf: parsedCert,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
target, _ := url.Parse(httpTarget)
|
target, _ := url.Parse(httpTarget)
|
||||||
|
|
||||||
httpsConfig := &http.Server{
|
httpsConfig := &http.Server{
|
||||||
Addr: fmt.Sprintf(":%d", port),
|
ReadHeaderTimeout: headerTimeout,
|
||||||
TLSConfig: &tls.Config{Certificates: []tls.Certificate{cert}},
|
Addr: fmt.Sprintf(":%d", port),
|
||||||
Handler: http.HandlerFunc(httputil.NewSingleHostReverseProxy(target).ServeHTTP),
|
TLSConfig: &tls.Config{Certificates: []tls.Certificate{cert}},
|
||||||
|
Handler: http.HandlerFunc(httputil.NewSingleHostReverseProxy(target).ServeHTTP),
|
||||||
}
|
}
|
||||||
return httpsConfig.ListenAndServeTLS("", "")
|
return httpsConfig.ListenAndServeTLS("", "")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Exit) handleCertificateEvent(incomingEvent *nostr.IncomingEvent, ctx context.Context, cert tls.Certificate) (tls.Certificate, error) {
|
||||||
|
slog.Info("found certificate event", "certificate", incomingEvent.Content)
|
||||||
|
// load private key from file
|
||||||
|
privateKeyEvent := e.pool.QuerySingle(ctx, e.config.NostrRelays, nostr.Filter{
|
||||||
|
Authors: []string{e.publicKey},
|
||||||
|
Kinds: []int{protocol.KindPrivateKeyEvent},
|
||||||
|
Tags: nostr.TagMap{"p": []string{e.publicKey}},
|
||||||
|
})
|
||||||
|
if privateKeyEvent == nil {
|
||||||
|
return tls.Certificate{}, errNoCertificateEvent
|
||||||
|
}
|
||||||
|
sharedKey, err := nip04.ComputeSharedSecret(privateKeyEvent.PubKey, e.config.NostrPrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return tls.Certificate{}, fmt.Errorf("failed to compute shared key: %w", err)
|
||||||
|
}
|
||||||
|
decodedMessage, err := nip04.Decrypt(privateKeyEvent.Content, sharedKey)
|
||||||
|
if err != nil {
|
||||||
|
return tls.Certificate{}, fmt.Errorf("failed to decrypt private key: %w", err)
|
||||||
|
}
|
||||||
|
message, err := protocol.UnmarshalJSON([]byte(decodedMessage))
|
||||||
|
if err != nil {
|
||||||
|
return tls.Certificate{}, fmt.Errorf("failed to unmarshal message: %w", err)
|
||||||
|
}
|
||||||
|
block, _ := pem.Decode(message.Data)
|
||||||
|
if block == nil {
|
||||||
|
_, err = fmt.Fprintf(os.Stderr, "error: failed to decode PEM block containing private key\n")
|
||||||
|
if err != nil {
|
||||||
|
return tls.Certificate{}, fmt.Errorf("failed to write error: %w", err)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got, want := block.Type, "RSA PRIVATE KEY"; got != want {
|
||||||
|
_, err = fmt.Fprintf(os.Stderr, "error: decoded PEM block of type %s, but wanted %s", got, want)
|
||||||
|
if err != nil {
|
||||||
|
return tls.Certificate{}, fmt.Errorf("failed to write error: %w", err)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return tls.Certificate{}, fmt.Errorf("failed to parse private key: %w", err)
|
||||||
|
}
|
||||||
|
certBlock, _ := pem.Decode([]byte(incomingEvent.Content))
|
||||||
|
if certBlock == nil {
|
||||||
|
_, err = fmt.Fprintf(os.Stderr, "Failed to parse certificate PEM.")
|
||||||
|
if err != nil {
|
||||||
|
return tls.Certificate{}, fmt.Errorf("failed to write error: %w", err)
|
||||||
|
}
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedCert, err := x509.ParseCertificate(certBlock.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return tls.Certificate{}, fmt.Errorf("failed to parse certificate: %w", err)
|
||||||
|
}
|
||||||
|
cert = tls.Certificate{
|
||||||
|
Certificate: [][]byte{certBlock.Bytes},
|
||||||
|
PrivateKey: priv,
|
||||||
|
Leaf: parsedCert,
|
||||||
|
}
|
||||||
|
return cert, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
tenYears = 0 * 365 * 24 * time.Hour
|
||||||
|
keySize = 2048
|
||||||
|
limit = 128
|
||||||
|
chmod = 0644
|
||||||
|
)
|
||||||
|
|
||||||
func (e *Exit) createAndStoreCertificateData(ctx context.Context) (*tls.Certificate, error) {
|
func (e *Exit) createAndStoreCertificateData(ctx context.Context) (*tls.Certificate, error) {
|
||||||
priv, _ := rsa.GenerateKey(rand.Reader, 2048)
|
priv, _ := rsa.GenerateKey(rand.Reader, keySize)
|
||||||
notBefore := time.Now()
|
notBefore := time.Now()
|
||||||
notAfter := notBefore.Add(10 * 365 * 24 * time.Hour)
|
notAfter := notBefore.Add(tenYears)
|
||||||
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), limit)
|
||||||
serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
|
serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
|
||||||
domain, _ := e.getDomain()
|
domain, _ := e.getDomain()
|
||||||
|
|
||||||
@ -126,7 +160,7 @@ func (e *Exit) createAndStoreCertificateData(ctx context.Context) (*tls.Certific
|
|||||||
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
|
certPEM := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certBytes})
|
||||||
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
|
keyPEM := pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)})
|
||||||
// save key pem to file
|
// save key pem to file
|
||||||
err := os.WriteFile(fmt.Sprintf("%s.key", e.publicKey), keyPEM, 0644)
|
err := os.WriteFile(fmt.Sprintf("%s.key", e.publicKey), keyPEM, chmod)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package exit
|
package exit
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"log/slog"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -33,8 +33,8 @@ func (mm *MutexMap) Unlock(id string) {
|
|||||||
mutex, ok := mm.m[id]
|
mutex, ok := mm.m[id]
|
||||||
mm.mu.Unlock()
|
mm.mu.Unlock()
|
||||||
if !ok {
|
if !ok {
|
||||||
panic(fmt.Sprintf("tried to unlock mutex for non-existent id %s", id))
|
slog.Error("mutex not found", "id", id)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex.Unlock()
|
mutex.Unlock()
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package exit
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
@ -12,9 +14,11 @@ import (
|
|||||||
|
|
||||||
const ten = 10
|
const ten = 10
|
||||||
|
|
||||||
|
var errNoPublicKey = errors.New("no public key found")
|
||||||
|
|
||||||
func (e *Exit) announceExitNode(ctx context.Context) error {
|
func (e *Exit) announceExitNode(ctx context.Context) error {
|
||||||
if !e.config.Public {
|
if !e.config.Public {
|
||||||
return nil
|
return errNoPublicKey
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
@ -45,25 +49,28 @@ func (e *Exit) announceExitNode(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Exit) DeleteEvent(ctx context.Context, ev *nostr.Event) error {
|
func (e *Exit) DeleteEvent(ctx context.Context, event *nostr.Event) error {
|
||||||
for _, responseRelay := range e.config.NostrRelays {
|
for _, responseRelay := range e.config.NostrRelays {
|
||||||
var relay *nostr.Relay
|
var relay *nostr.Relay
|
||||||
relay, err := e.pool.EnsureRelay(responseRelay)
|
relay, err := e.pool.EnsureRelay(responseRelay)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to ensure relay: %w", err)
|
||||||
}
|
}
|
||||||
event := nostr.Event{
|
event := nostr.Event{
|
||||||
CreatedAt: nostr.Now(),
|
CreatedAt: nostr.Now(),
|
||||||
PubKey: e.publicKey,
|
PubKey: e.publicKey,
|
||||||
Kind: nostr.KindDeletion,
|
Kind: nostr.KindDeletion,
|
||||||
Tags: nostr.Tags{
|
Tags: nostr.Tags{
|
||||||
nostr.Tag{"e", ev.ID},
|
nostr.Tag{"e", event.ID},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err = event.Sign(e.config.NostrPrivateKey)
|
err = event.Sign(e.config.NostrPrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to sign event: %w", err)
|
||||||
|
}
|
||||||
err = relay.Publish(ctx, event)
|
err = relay.Publish(ctx, event)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("failed to publish event: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
Loading…
Reference in New Issue
Block a user