diff --git a/config.go b/config.go index e345b4e3f..459fc9b86 100644 --- a/config.go +++ b/config.go @@ -1596,7 +1596,7 @@ func ValidateConfig(cfg Config, interceptor signal.Interceptor, fileParser, // Finally, ensure that the user's color is correctly formatted, // otherwise the server will not be able to start after the unlocking // the wallet. - _, err = parseHexColor(cfg.Color) + _, err = lncfg.ParseHexColor(cfg.Color) if err != nil { return nil, mkErr("unable to parse node color: %v", err) } diff --git a/lncfg/color.go b/lncfg/color.go new file mode 100644 index 000000000..75708684a --- /dev/null +++ b/lncfg/color.go @@ -0,0 +1,34 @@ +package lncfg + +import ( + "encoding/hex" + "errors" + "image/color" + "regexp" +) + +var ( + // validColorRegexp is a regexp that lets you check if a particular + // color string matches the standard hex color format #RRGGBB. + validColorRegexp = regexp.MustCompile("^#[A-Fa-f0-9]{6}$") +) + +// ParseHexColor takes a hex string representation of a color in the +// form "#RRGGBB", parses the hex color values, and returns a color.RGBA +// struct of the same color. +func ParseHexColor(colorStr string) (color.RGBA, error) { + // Check if the hex color string is a valid color representation. + if !validColorRegexp.MatchString(colorStr) { + return color.RGBA{}, errors.New("color must be specified " + + "using a hexadecimal value in the form #RRGGBB") + } + + // Decode the hex color string to bytes. + // The resulting byte array is in the form [R, G, B]. + colorBytes, err := hex.DecodeString(colorStr[1:]) + if err != nil { + return color.RGBA{}, err + } + + return color.RGBA{R: colorBytes[0], G: colorBytes[1], B: colorBytes[2]}, nil +} diff --git a/lncfg/color_test.go b/lncfg/color_test.go new file mode 100644 index 000000000..b4a0c9308 --- /dev/null +++ b/lncfg/color_test.go @@ -0,0 +1,43 @@ +package lncfg + +import ( + "testing" +) + +func TestParseHexColor(t *testing.T) { + var colorTestCases = []struct { + test string + valid bool // If valid format + R byte + G byte + B byte + }{ + {"#123", false, 0, 0, 0}, + {"#1234567", false, 0, 0, 0}, + {"$123456", false, 0, 0, 0}, + {"#12345+", false, 0, 0, 0}, + {"#fFGG00", false, 0, 0, 0}, + {"", false, 0, 0, 0}, + {"#123456", true, 0x12, 0x34, 0x56}, + {"#C0FfeE", true, 0xc0, 0xff, 0xee}, + } + + // Perform the table driven tests. + for _, ct := range colorTestCases { + + color, err := ParseHexColor(ct.test) + if !ct.valid && err == nil { + t.Fatalf("Invalid color string: %s, should return "+ + "error, but did not", ct.test) + } + + if ct.valid && err != nil { + t.Fatalf("Color %s valid to parse: %s", ct.test, err) + } + + // Ensure that the string to hex decoding is working properly. + if color.R != ct.R || color.G != ct.G || color.B != ct.B { + t.Fatalf("Color %s incorrectly parsed as %v", ct.test, color) + } + } +} diff --git a/server.go b/server.go index 1aceebc14..8ac2e7ad3 100644 --- a/server.go +++ b/server.go @@ -6,11 +6,9 @@ import ( "crypto/rand" "encoding/hex" "fmt" - "image/color" "math/big" prand "math/rand" "net" - "regexp" "strconv" "strings" "sync" @@ -116,10 +114,6 @@ var ( // gracefully exiting. ErrServerShuttingDown = errors.New("server is shutting down") - // validColorRegexp is a regexp that lets you check if a particular - // color string matches the standard hex color format #RRGGBB. - validColorRegexp = regexp.MustCompile("^#[A-Fa-f0-9]{6}$") - // MaxFundingAmount is a soft-limit of the maximum channel size // currently accepted within the Lightning Protocol. This is // defined in BOLT-0002, and serves as an initial precautionary limit @@ -772,7 +766,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, // the network. // // We'll start by parsing the node color from configuration. - color, err := parseHexColor(cfg.Color) + color, err := lncfg.ParseHexColor(cfg.Color) if err != nil { srvrLog.Errorf("unable to parse color: %v\n", err) return nil, err @@ -4196,26 +4190,6 @@ func (s *server) Peers() []*peer.Brontide { return peers } -// parseHexColor takes a hex string representation of a color in the -// form "#RRGGBB", parses the hex color values, and returns a color.RGBA -// struct of the same color. -func parseHexColor(colorStr string) (color.RGBA, error) { - // Check if the hex color string is a valid color representation. - if !validColorRegexp.MatchString(colorStr) { - return color.RGBA{}, errors.New("Color must be specified " + - "using a hexadecimal value in the form #RRGGBB") - } - - // Decode the hex color string to bytes. - // The resulting byte array is in the form [R, G, B]. - colorBytes, err := hex.DecodeString(colorStr[1:]) - if err != nil { - return color.RGBA{}, err - } - - return color.RGBA{R: colorBytes[0], G: colorBytes[1], B: colorBytes[2]}, nil -} - // computeNextBackoff uses a truncated exponential backoff to compute the next // backoff using the value of the exiting backoff. The returned duration is // randomized in either direction by 1/20 to prevent tight loops from diff --git a/server_test.go b/server_test.go index 48b2f652d..317a3a483 100644 --- a/server_test.go +++ b/server_test.go @@ -22,44 +22,6 @@ import ( "github.com/lightningnetwork/lnd/lncfg" ) -func TestParseHexColor(t *testing.T) { - var colorTestCases = []struct { - test string - valid bool // If valid format - R byte - G byte - B byte - }{ - {"#123", false, 0, 0, 0}, - {"#1234567", false, 0, 0, 0}, - {"$123456", false, 0, 0, 0}, - {"#12345+", false, 0, 0, 0}, - {"#fFGG00", false, 0, 0, 0}, - {"", false, 0, 0, 0}, - {"#123456", true, 0x12, 0x34, 0x56}, - {"#C0FfeE", true, 0xc0, 0xff, 0xee}, - } - - // Perform the table driven tests. - for _, ct := range colorTestCases { - - color, err := parseHexColor(ct.test) - if !ct.valid && err == nil { - t.Fatalf("Invalid color string: %s, should return "+ - "error, but did not", ct.test) - } - - if ct.valid && err != nil { - t.Fatalf("Color %s valid to parse: %s", ct.test, err) - } - - // Ensure that the string to hex decoding is working properly. - if color.R != ct.R || color.G != ct.G || color.B != ct.B { - t.Fatalf("Color %s incorrectly parsed as %v", ct.test, color) - } - } -} - // TestTLSAutoRegeneration creates an expired TLS certificate, to test that a // new TLS certificate pair is regenerated when the old pair expires. This is // necessary because the pair expires after a little over a year.