From e41b838d8f119b4c71f7a27995c5a941185164c5 Mon Sep 17 00:00:00 2001
From: Neil Alexander <neilalexander@users.noreply.github.com>
Date: Sat, 28 Oct 2023 21:28:38 +0100
Subject: [PATCH] Don't panic at startup when duplicate peers are configured

Fixes #1077
---
 src/core/options.go      | 10 +++++++++-
 src/core/options_test.go | 41 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 src/core/options_test.go

diff --git a/src/core/options.go b/src/core/options.go
index ffbdae73..581c033b 100644
--- a/src/core/options.go
+++ b/src/core/options.go
@@ -13,7 +13,15 @@ func (c *Core) _applyOption(opt SetupOption) (err error) {
 		if err != nil {
 			return fmt.Errorf("unable to parse peering URI: %w", err)
 		}
-		return c.links.add(u, v.SourceInterface, linkTypePersistent)
+		err = c.links.add(u, v.SourceInterface, linkTypePersistent)
+		switch err {
+		case ErrLinkAlreadyConfigured:
+			// Don't return this error, otherwise we'll panic at startup
+			// if there are multiple of the same peer configured
+			return nil
+		default:
+			return err
+		}
 	case ListenAddress:
 		c.config._listeners[v] = struct{}{}
 	case NodeInfo:
diff --git a/src/core/options_test.go b/src/core/options_test.go
new file mode 100644
index 00000000..bab22fb1
--- /dev/null
+++ b/src/core/options_test.go
@@ -0,0 +1,41 @@
+package core
+
+import (
+	"net/url"
+	"testing"
+
+	"github.com/yggdrasil-network/yggdrasil-go/src/config"
+)
+
+// Tests that duplicate peers in the configuration file
+// won't cause an error when the node starts. Otherwise
+// we can panic unnecessarily.
+func TestDuplicatePeerAtStartup(t *testing.T) {
+	cfg := config.GenerateConfig()
+	for i := 0; i < 5; i++ {
+		cfg.Peers = append(cfg.Peers, "tcp://1.2.3.4:4321")
+	}
+	if _, err := New(cfg.Certificate, nil); err != nil {
+		t.Fatal(err)
+	}
+}
+
+// Tests that duplicate peers given to us through the
+// API will still error as expected, even if they didn't
+// at startup. We expect to notify the user through the
+// admin socket if they try to add a peer that is already
+// configured.
+func TestDuplicatePeerFromAPI(t *testing.T) {
+	cfg := config.GenerateConfig()
+	c, err := New(cfg.Certificate, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	u, _ := url.Parse("tcp://1.2.3.4:4321")
+	if err := c.AddPeer(u, ""); err != nil {
+		t.Fatalf("Adding peer failed on first attempt: %s", err)
+	}
+	if err := c.AddPeer(u, ""); err == nil {
+		t.Fatalf("Adding peer should have failed on second attempt")
+	}
+}