From c910edae6bcc9c56c7353e4d2c01a0c4eb21cf15 Mon Sep 17 00:00:00 2001 From: urgentquest Date: Fri, 7 Mar 2025 01:35:21 +0000 Subject: [PATCH 1/6] Make sendMessage() validate replies --- auth.go | 22 ++++------------------ client.go | 38 ++++++++++++++++++++++++++++++++------ dest.go | 3 --- naming.go | 10 ++-------- replyParser.go | 15 +++++++++++++++ sessions.go | 10 ++-------- stream.go | 24 ++++-------------------- 7 files changed, 59 insertions(+), 63 deletions(-) diff --git a/auth.go b/auth.go index 8728dc9..d9688ff 100644 --- a/auth.go +++ b/auth.go @@ -1,47 +1,33 @@ package gosam -import "fmt" - // SetupAuth sends the AUTH ENABLE command and immediately sets up a new Username and // Password from the arguments func (c *Client) SetupAuth(user, password string) error { - r, err := c.sendCmd("AUTH ENABLE\n") + _, err := c.sendCmd("AUTH ENABLE\n") if err != nil { return err } - if r.Topic != "AUTH" { - return fmt.Errorf("SetupAuth Unknown Reply: %+v\n", r) - } - r, err = c.sendCmd("AUTH %s %s\n", user, password) + _, err = c.sendCmd("AUTH %s %s\n", user, password) if err != nil { return err } - if r.Topic != "AUTH" { - return fmt.Errorf("SetupAuth Unknown Reply: %+v\n", r) - } return nil } // TeardownAuth sends the AUTH DISABLE command but does not remove the Username and // Password from the client PasswordManager func (c *Client) TeardownAuth() error { - r, err := c.sendCmd("AUTH DISABLE\n") + _, err := c.sendCmd("AUTH DISABLE\n") if err != nil { return err } - if r.Topic != "AUTH" { - return fmt.Errorf("TeardownAuth Unknown Reply: %+v\n", r) - } return nil } func (c *Client) RemoveAuthUser(user string) error { - r, err := c.sendCmd("AUTH REMOVE %s\n", user) + _, err := c.sendCmd("AUTH REMOVE %s\n", user) if err != nil { return err } - if r.Topic != "AUTH" { - return fmt.Errorf("RemoveAuthUser Unknown Reply: %+v\n", r) - } return nil } diff --git a/client.go b/client.go index c32b130..d14f556 100644 --- a/client.go +++ b/client.go @@ -226,11 +226,7 @@ func (c *Client) hello() error { return err } - if r.Topic != "HELLO" { - return fmt.Errorf("Client Hello Unknown Reply: %+v\n", r) - } - - if r.Pairs["RESULT"] != "OK" { + if !r.IsOk() { return fmt.Errorf("Handshake did not succeed\nReply:%+v\n", r) } @@ -248,7 +244,37 @@ func (c *Client) sendCmd(str string, args ...interface{}) (*Reply, error) { return nil, err } - return parseReply(line) + r, err := parseReply(line) + if err != nil { + return nil, err + } + + if err := c.validateResponse(str, r); err != nil { + return nil, fmt.Errorf("unrecogized reply: %+v\n%v", r, err) + } + + return r, nil +} + +func (c *Client) validateResponse(command string, reply *Reply) error { + expectedTypesMap := map[string]string{ + "HELLO": "REPLY", + "DEST": "REPLY", + "NAMING": "REPLY", + "SESSION": "STATUS", + "STREAM": "STATUS", + } + commandTopic := strings.SplitN(command, "", 1)[0] + + if commandTopic != reply.Topic { + return fmt.Errorf("unrecogized reply topic. expecting: %v, got: %v", commandTopic, reply.Topic) + } + + if expectedTypesMap[commandTopic] != reply.Type { + return fmt.Errorf("unrecogized reply type. expecting: %v, got: %v", expectedTypesMap[commandTopic], reply.Type) + } + + return nil } // Close the underlying socket to SAM diff --git a/dest.go b/dest.go index 893dc45..baffac4 100644 --- a/dest.go +++ b/dest.go @@ -46,9 +46,6 @@ func (c *Client) NewDestination(kind ...string) (string, string, error) { if err != nil { return "", "", err } - if r.Topic != "DEST" { - return "", "", fmt.Errorf("NewDestination Unknown Reply: %+v\n", r) - } return r.Pairs["PRIV"], r.Pairs["PUB"], nil } diff --git a/naming.go b/naming.go index aaa7e14..9fd3d89 100644 --- a/naming.go +++ b/naming.go @@ -15,14 +15,8 @@ func (c *Client) Lookup(name string) (string, error) { return "", nil } - // TODO: move check into sendCmd() - if r.Topic != "NAMING" || r.Type != "REPLY" { - return "", fmt.Errorf("Naming Unknown Reply: %s, %s\n", r.Topic, r.Type) - } - - result := r.Pairs["RESULT"] - if result != "OK" { - return "", ReplyError{result, r} + if !r.IsOk() { + return "", ReplyError{r.GetResult(), r} } if r.Pairs["NAME"] != name { diff --git a/replyParser.go b/replyParser.go index 8035105..98a9f4e 100644 --- a/replyParser.go +++ b/replyParser.go @@ -38,6 +38,21 @@ type Reply struct { Pairs map[string]string } +func (r *Reply) IsOk() bool { + return r.Pairs["RESULT"] == ResultOk +} + +func (r *Reply) GetResult() string { + result, ok := r.Pairs["RESULT"] + + if !ok { + // TODO Add some debug output + return "" + } + + return result +} + func parseReply(line string) (*Reply, error) { line = strings.TrimSpace(line) parts := strings.Split(line, " ") diff --git a/sessions.go b/sessions.go index 1628975..907d4c6 100644 --- a/sessions.go +++ b/sessions.go @@ -1,7 +1,7 @@ package gosam import ( - "fmt" + // "math" "math/rand" "time" @@ -33,13 +33,7 @@ func (c *Client) CreateSession(style, dest string) (string, error) { return "", err } - // TODO: move check into sendCmd() - if r.Topic != "SESSION" || r.Type != "STATUS" { - return "", fmt.Errorf("Session Unknown Reply: %+v\n", r) - } - - result := r.Pairs["RESULT"] - if result != "OK" { + if !r.IsOk() { return "", ReplyError{ResultKeyNotFound, r} } c.destination = r.Pairs["DESTINATION"] diff --git a/stream.go b/stream.go index 81231a9..384d3c1 100644 --- a/stream.go +++ b/stream.go @@ -1,9 +1,5 @@ package gosam -import ( - "fmt" -) - // StreamConnect asks SAM for a TCP-Like connection to dest, has to be called on a new Client func (c *Client) StreamConnect(dest string) error { if dest == "" { @@ -14,14 +10,8 @@ func (c *Client) StreamConnect(dest string) error { return err } - // TODO: move check into sendCmd() - if r.Topic != "STREAM" || r.Type != "STATUS" { - return fmt.Errorf("Stream Connect Unknown Reply: %+v\n", r) - } - - result := r.Pairs["RESULT"] - if result != "OK" { - return ReplyError{result, r} + if !r.IsOk() { + return ReplyError{r.GetResult(), r} } return nil @@ -34,14 +24,8 @@ func (c *Client) StreamAccept() (*Reply, error) { return nil, err } - // TODO: move check into sendCmd() - if r.Topic != "STREAM" || r.Type != "STATUS" { - return nil, fmt.Errorf("Stream Accept Unknown Reply: %+v\n", r) - } - - result := r.Pairs["RESULT"] - if result != "OK" { - return nil, ReplyError{result, r} + if !r.IsOk() { + return nil, ReplyError{r.GetResult(), r} } return r, nil From 6f02aa69e804ac30b58a90afa6f7166f29f52909 Mon Sep 17 00:00:00 2001 From: urgentquest Date: Sat, 8 Mar 2025 23:20:46 +0000 Subject: [PATCH 2/6] rename validateResponse() to validateReply() for consitency, correct a typo in the splitN invocation, add basic command validation --- client.go | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/client.go b/client.go index d14f556..dc658cd 100644 --- a/client.go +++ b/client.go @@ -77,6 +77,8 @@ var SAMsigTypes = []string{ var ValidSAMCommands = []string{ "HELLO", + "DEST", + "NAMING", "SESSION", "STREAM", } @@ -235,6 +237,10 @@ func (c *Client) hello() error { // helper to send one command and parse the reply by sam func (c *Client) sendCmd(str string, args ...interface{}) (*Reply, error) { + if err := validateCommand(str); err != nil { + return nil, err + } + if _, err := fmt.Fprintf(c.SamConn, str, args...); err != nil { return nil, err } @@ -249,14 +255,26 @@ func (c *Client) sendCmd(str string, args ...interface{}) (*Reply, error) { return nil, err } - if err := c.validateResponse(str, r); err != nil { + if err := c.validateReply(str, r); err != nil { return nil, fmt.Errorf("unrecogized reply: %+v\n%v", r, err) } return r, nil } -func (c *Client) validateResponse(command string, reply *Reply) error { +func validateCommand(str string) error { + topic := strings.SplitN(str, " ", 1)[0] + for _, x := range ValidSAMCommands { + if x == topic { + return nil + } + } + + return fmt.Errorf("unsupported sam command %v", topic) + +} + +func (c *Client) validateReply(command string, reply *Reply) error { expectedTypesMap := map[string]string{ "HELLO": "REPLY", "DEST": "REPLY", @@ -264,7 +282,7 @@ func (c *Client) validateResponse(command string, reply *Reply) error { "SESSION": "STATUS", "STREAM": "STATUS", } - commandTopic := strings.SplitN(command, "", 1)[0] + commandTopic := strings.SplitN(command, " ", 1)[0] if commandTopic != reply.Topic { return fmt.Errorf("unrecogized reply topic. expecting: %v, got: %v", commandTopic, reply.Topic) From eebe8c5cb4e2d685972e0c99ab4100020397958b Mon Sep 17 00:00:00 2001 From: urgentquest Date: Fri, 9 May 2025 00:41:20 +0000 Subject: [PATCH 3/6] - Unbreak things by properly validate command topic - Replace fmt.ErrorF() with errors.New() where no actual formatting requested - Hanle edge cases with no username/password in `Client.hello()` - Make go-staticcheck happier --- client.go | 20 ++++++++++++----- dest.go | 2 +- dial.go | 4 ++-- naming.go | 2 +- options.go | 65 +++++++++++++++++++++++++++--------------------------- 5 files changed, 52 insertions(+), 41 deletions(-) diff --git a/client.go b/client.go index dc658cd..b67887e 100644 --- a/client.go +++ b/client.go @@ -222,21 +222,31 @@ func (c *Client) samaddr() string { // send the initial handshake command and check that the reply is ok func (c *Client) hello() error { + var r *Reply + var err error + + if c.getUser() == "" { + r, err = c.sendCmd("HELLO VERSION MIN=3.%d MAX=3.%d\n", c.sammin, c.sammax) + + } else if c.getUser() != "" && c.getPass() == "" { + r, err = c.sendCmd("HELLO VERSION MIN=3.%d MAX=3.%d %s\n", c.sammin, c.sammax, c.getUser()) + } else { + r, err = c.sendCmd("HELLO VERSION MIN=3.%d MAX=3.%d %s %s\n", c.sammin, c.sammax, c.getUser(), c.getPass()) + } - r, err := c.sendCmd("HELLO VERSION MIN=3.%d MAX=3.%d %s %s\n", c.sammin, c.sammax, c.getUser(), c.getPass()) if err != nil { return err } if !r.IsOk() { - return fmt.Errorf("Handshake did not succeed\nReply:%+v\n", r) + return fmt.Errorf("handshake did not succeed\nReply:%+v", r) } return nil } // helper to send one command and parse the reply by sam -func (c *Client) sendCmd(str string, args ...interface{}) (*Reply, error) { +func (c *Client) sendCmd(str string, args ...any) (*Reply, error) { if err := validateCommand(str); err != nil { return nil, err } @@ -263,7 +273,7 @@ func (c *Client) sendCmd(str string, args ...interface{}) (*Reply, error) { } func validateCommand(str string) error { - topic := strings.SplitN(str, " ", 1)[0] + topic, _, _ := strings.Cut(str, " ") for _, x := range ValidSAMCommands { if x == topic { return nil @@ -282,7 +292,7 @@ func (c *Client) validateReply(command string, reply *Reply) error { "SESSION": "STATUS", "STREAM": "STATUS", } - commandTopic := strings.SplitN(command, " ", 1)[0] + commandTopic, _, _ := strings.Cut(command, " ") if commandTopic != reply.Topic { return fmt.Errorf("unrecogized reply topic. expecting: %v, got: %v", commandTopic, reply.Topic) diff --git a/dest.go b/dest.go index baffac4..6ce994a 100644 --- a/dest.go +++ b/dest.go @@ -26,7 +26,7 @@ func validateKind(kind string) (string, error) { if kint >= 0 && kint <= 7 { return validateKindInner(kind), nil } - return "SIGNATURE_TYPE=7", fmt.Errorf("Invalid sigType: %s", kind) + return "SIGNATURE_TYPE=7", fmt.Errorf("invalid sigType: %s", kind) } // Generate a new destination and return the base64 encoded string diff --git a/dial.go b/dial.go index 1c92085..625590f 100644 --- a/dial.go +++ b/dial.go @@ -2,7 +2,7 @@ package gosam import ( "context" - "fmt" + "errors" "log" "net" "strings" @@ -66,7 +66,7 @@ func (c *Client) DialDatagramContextFree(addr string) (*DatagramConn, error) { return nil, err } - return nil, fmt.Errorf("Datagram support is not finished yet, come back later`") + return nil, errors.New("datagram support is not finished yet, come back later") } // DialStreamingContextFree is a "Dialer" for "Client-Like" Streaming connections. diff --git a/naming.go b/naming.go index 9fd3d89..707c8df 100644 --- a/naming.go +++ b/naming.go @@ -22,7 +22,7 @@ func (c *Client) Lookup(name string) (string, error) { if r.Pairs["NAME"] != name { // somehow different on i2pd if r.Pairs["NAME"] != "ME" { - return "", fmt.Errorf("Lookup() Replyed to another name.\nWanted:%s\nGot: %+v\n", name, r) + return "", fmt.Errorf("Lookup() Replyed to another name.\nWanted:%s\nGot: %+v", name, r) } fmt.Fprintln(os.Stderr, "WARNING: Lookup() Replyed to another name. assuming i2pd c++ fluke") } diff --git a/options.go b/options.go index 41855ca..dbae484 100644 --- a/options.go +++ b/options.go @@ -1,6 +1,7 @@ package gosam import ( + "errors" "fmt" "strconv" "strings" @@ -21,11 +22,11 @@ func SetAddr(s ...string) func(*Client) error { c.port = split[1] return nil } - return fmt.Errorf("Invalid port") + return errors.New("invalid port") } - return fmt.Errorf("Invalid port; non-number") + return errors.New("invalid port; non-number") } - return fmt.Errorf("Invalid address; use host:port %s", split) + return fmt.Errorf("invalid address; use host:port %s", split) } else if len(s) == 2 { if i, err := strconv.Atoi(s[1]); err == nil { if i < 65536 { @@ -33,11 +34,11 @@ func SetAddr(s ...string) func(*Client) error { c.port = s[1] return nil } - return fmt.Errorf("Invalid port") + return errors.New("invalid port") } - return fmt.Errorf("Invalid port; non-number") + return errors.New("invalid port; non-number") } else { - return fmt.Errorf("Invalid address") + return errors.New("invalid address") } } } @@ -50,7 +51,7 @@ func SetAddrMixed(s string, i int) func(*Client) error { c.port = strconv.Itoa(i) return nil } - return fmt.Errorf("Invalid port") + return errors.New("invalid port") } } @@ -81,10 +82,10 @@ func SetPass(s string) func(*Client) error { func SetSAMMinVersion(i int) func(*Client) error { return func(c *Client) error { if i < 0 { - return fmt.Errorf("SAM version must be greater than or equal to 0") + return errors.New("SAM version must be greater than or equal to 0") } if i > 3 { - return fmt.Errorf("SAM version must be less than or equal to 3") + return errors.New("SAM version must be less than or equal to 3") } c.sammin = i return nil @@ -94,10 +95,10 @@ func SetSAMMinVersion(i int) func(*Client) error { func SetSAMMaxVersion(i int) func(*Client) error { return func(c *Client) error { if i < 0 { - return fmt.Errorf("SAM version must be greater than or equal to 0") + return errors.New("SAM version must be greater than or equal to 0") } if i > 3 { - return fmt.Errorf("SAM version must be less than or equal to 3") + return errors.New("SAM version must be less than or equal to 3") } c.sammin = i return nil @@ -125,13 +126,13 @@ func SetPort(s string) func(*Client) error { return func(c *Client) error { port, err := strconv.Atoi(s) if err != nil { - return fmt.Errorf("Invalid port; non-number") + return errors.New("invalid port; non-number") } if port < 65536 && port > -1 { c.port = s return nil } - return fmt.Errorf("Invalid port") + return errors.New("invalid port") } } @@ -142,7 +143,7 @@ func SetPortInt(i int) func(*Client) error { c.port = strconv.Itoa(i) return nil } - return fmt.Errorf("Invalid port") + return errors.New("invalid port") } } @@ -151,13 +152,13 @@ func SetFromPort(s string) func(*Client) error { return func(c *Client) error { port, err := strconv.Atoi(s) if err != nil { - return fmt.Errorf("Invalid port; non-number") + return errors.New("invalid port; non-number") } if port < 65536 && port > -1 { c.fromport = s return nil } - return fmt.Errorf("Invalid port") + return errors.New("invalid port") } } @@ -168,7 +169,7 @@ func SetFromPortInt(i int) func(*Client) error { c.fromport = strconv.Itoa(i) return nil } - return fmt.Errorf("Invalid port") + return errors.New("invalid port") } } @@ -177,13 +178,13 @@ func SetToPort(s string) func(*Client) error { return func(c *Client) error { port, err := strconv.Atoi(s) if err != nil { - return fmt.Errorf("Invalid port; non-number") + return errors.New("invalid port; non-number") } if port < 65536 && port > -1 { c.toport = s return nil } - return fmt.Errorf("Invalid port") + return errors.New("invalid port") } } @@ -194,7 +195,7 @@ func SetToPortInt(i int) func(*Client) error { c.fromport = strconv.Itoa(i) return nil } - return fmt.Errorf("Invalid port") + return errors.New("invalid port") } } @@ -214,7 +215,7 @@ func SetInLength(u uint) func(*Client) error { c.inLength = u return nil } - return fmt.Errorf("Invalid inbound tunnel length") + return errors.New("invalid inbound tunnel length") } } @@ -225,7 +226,7 @@ func SetOutLength(u uint) func(*Client) error { c.outLength = u return nil } - return fmt.Errorf("Invalid outbound tunnel length") + return errors.New("invalid outbound tunnel length") } } @@ -236,7 +237,7 @@ func SetInVariance(i int) func(*Client) error { c.inVariance = i return nil } - return fmt.Errorf("Invalid inbound tunnel length") + return errors.New("invalid inbound tunnel length") } } @@ -247,7 +248,7 @@ func SetOutVariance(i int) func(*Client) error { c.outVariance = i return nil } - return fmt.Errorf("Invalid outbound tunnel variance") + return errors.New("invalid outbound tunnel variance") } } @@ -258,7 +259,7 @@ func SetInQuantity(u uint) func(*Client) error { c.inQuantity = u return nil } - return fmt.Errorf("Invalid inbound tunnel quantity") + return errors.New("invalid inbound tunnel quantity") } } @@ -269,7 +270,7 @@ func SetOutQuantity(u uint) func(*Client) error { c.outQuantity = u return nil } - return fmt.Errorf("Invalid outbound tunnel quantity") + return errors.New("invalid outbound tunnel quantity") } } @@ -280,7 +281,7 @@ func SetInBackups(u uint) func(*Client) error { c.inBackups = u return nil } - return fmt.Errorf("Invalid inbound tunnel backup quantity") + return errors.New("invalid inbound tunnel backup quantity") } } @@ -291,7 +292,7 @@ func SetOutBackups(u uint) func(*Client) error { c.outBackups = u return nil } - return fmt.Errorf("Invalid outbound tunnel backup quantity") + return errors.New("invalid outbound tunnel backup quantity") } } @@ -335,7 +336,7 @@ func SetReduceIdleTime(u uint) func(*Client) error { c.reduceIdleTime = u return nil } - return fmt.Errorf("Invalid reduce idle time %v", u) + return fmt.Errorf("invalid reduce idle time %v", u) } } @@ -346,7 +347,7 @@ func SetReduceIdleQuantity(u uint) func(*Client) error { c.reduceIdleQuantity = u return nil } - return fmt.Errorf("Invalid reduced tunnel quantity %v", u) + return fmt.Errorf("invalid reduced tunnel quantity %v", u) } } @@ -365,7 +366,7 @@ func SetCloseIdleTime(u uint) func(*Client) error { c.closeIdleTime = u return nil } - return fmt.Errorf("Invalid close idle time %v", u) + return fmt.Errorf("invalid close idle time %v", u) } } @@ -401,7 +402,7 @@ func SetSignatureType(s string) func(*Client) error { return nil } } - return fmt.Errorf("Invalid signature type specified at construction time") + return errors.New("invalid signature type specified at construction time") } } From 7ac12aa540d09dea25140e5c20b0a2e1bf2de2af Mon Sep 17 00:00:00 2001 From: urgentquest Date: Fri, 9 May 2025 00:45:40 +0000 Subject: [PATCH 4/6] - Remove unneeded `rand.Seed()` invocation. Not needed since go 1.20 - go-staticcheck --- replyParser.go | 4 ++-- sessions.go | 11 ----------- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/replyParser.go b/replyParser.go index 98a9f4e..31e80a0 100644 --- a/replyParser.go +++ b/replyParser.go @@ -57,7 +57,7 @@ func parseReply(line string) (*Reply, error) { line = strings.TrimSpace(line) parts := strings.Split(line, " ") if len(parts) < 3 { - return nil, fmt.Errorf("Malformed Reply.\n%s\n", line) + return nil, fmt.Errorf("malformed Reply.\n%s", line) } preParseReply := func() []string { val := "" @@ -98,7 +98,7 @@ func parseReply(line string) (*Reply, error) { kvPair := strings.SplitN(v, "=", 2) if kvPair != nil { if len(kvPair) != 2 { - return nil, fmt.Errorf("Malformed key-value-pair len != 2.\n%s\n", kvPair) + return nil, fmt.Errorf("malformed key-value-pair len != 2.\n%s", kvPair) } } r.Pairs[kvPair[0]] = kvPair[len(kvPair)-1] diff --git a/sessions.go b/sessions.go index 907d4c6..2b74e9c 100644 --- a/sessions.go +++ b/sessions.go @@ -1,16 +1,5 @@ package gosam -import ( - - // "math" - "math/rand" - "time" -) - -func init() { - rand.Seed(time.Now().UnixNano()) -} - // CreateSession creates a new Session of type style, with an optional destination. // an empty destination is interpreted as "TRANSIENT" // Returns the destination for the new Client or an error. From 7fc3f35fbff669c98f9b9856c849dffb4282bace Mon Sep 17 00:00:00 2001 From: urgentquest Date: Fri, 9 May 2025 00:58:21 +0000 Subject: [PATCH 5/6] spacing. no functional changes --- client.go | 1 - 1 file changed, 1 deletion(-) diff --git a/client.go b/client.go index b67887e..e1fb0d3 100644 --- a/client.go +++ b/client.go @@ -227,7 +227,6 @@ func (c *Client) hello() error { if c.getUser() == "" { r, err = c.sendCmd("HELLO VERSION MIN=3.%d MAX=3.%d\n", c.sammin, c.sammax) - } else if c.getUser() != "" && c.getPass() == "" { r, err = c.sendCmd("HELLO VERSION MIN=3.%d MAX=3.%d %s\n", c.sammin, c.sammax, c.getUser()) } else { From 893873cca245941f6ed24d636f1d5f958192a103 Mon Sep 17 00:00:00 2001 From: urgentquest Date: Sun, 11 May 2025 21:59:16 +0000 Subject: [PATCH 6/6] tests: make it compatible with i2pd --- naming_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/naming_test.go b/naming_test.go index 1fe1a42..ce2b986 100644 --- a/naming_test.go +++ b/naming_test.go @@ -25,8 +25,8 @@ func TestClientLookupInvalid(t *testing.T) { if !ok { t.Fatalf("client.Lookup() should return a ReplyError") } - if repErr.Result != ResultKeyNotFound { - t.Errorf("client.Lookup() should throw an ResultKeyNotFound error.\nGot:%+v%s%s\n", repErr, "!=", ResultKeyNotFound) + if repErr.Result != ResultKeyNotFound && repErr.Result != ResultInvalidKey { + t.Errorf("client.Lookup() should either throw an ResultKeyNotFound(i2p) or ResultInvalidKey(i2pd) error.\nGot:%+v%s%s\n", repErr, "!=", ResultKeyNotFound) } if err := client.Close(); err != nil { t.Fatalf("client.Close() Error: %q\n", err)