diff --git a/main.go b/main.go index 68e3ddaf..6af69429 100644 --- a/main.go +++ b/main.go @@ -74,8 +74,9 @@ func handleConn(conn *minecraft.Conn, listener *minecraft.Listener, config confi return } if err := serverConn.WritePacket(pk); err != nil { - if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok { - _ = listener.Disconnect(conn, disconnect.Error()) + var disc minecraft.DisconnectError + if ok := errors.As(err, &disc); ok { + _ = listener.Disconnect(conn, disc.Error()) } return } @@ -87,8 +88,9 @@ func handleConn(conn *minecraft.Conn, listener *minecraft.Listener, config confi for { pk, err := serverConn.ReadPacket() if err != nil { - if disconnect, ok := errors.Unwrap(err).(minecraft.DisconnectError); ok { - _ = listener.Disconnect(conn, disconnect.Error()) + var disc minecraft.DisconnectError + if ok := errors.As(err, &disc); ok { + _ = listener.Disconnect(conn, disc.Error()) } return } @@ -111,30 +113,30 @@ func readConfig() config { if _, err := os.Stat("config.toml"); os.IsNotExist(err) { f, err := os.Create("config.toml") if err != nil { - log.Fatalf("error creating config: %v", err) + log.Fatalf("create config: %v", err) } data, err := toml.Marshal(c) if err != nil { - log.Fatalf("error encoding default config: %v", err) + log.Fatalf("encode default config: %v", err) } if _, err := f.Write(data); err != nil { - log.Fatalf("error writing encoded default config: %v", err) + log.Fatalf("write default config: %v", err) } _ = f.Close() } data, err := os.ReadFile("config.toml") if err != nil { - log.Fatalf("error reading config: %v", err) + log.Fatalf("read config: %v", err) } if err := toml.Unmarshal(data, &c); err != nil { - log.Fatalf("error decoding config: %v", err) + log.Fatalf("decode config: %v", err) } if c.Connection.LocalAddress == "" { c.Connection.LocalAddress = "0.0.0.0:19132" } data, _ = toml.Marshal(c) if err := os.WriteFile("config.toml", data, 0644); err != nil { - log.Fatalf("error writing config file: %v", err) + log.Fatalf("write config: %v", err) } return c } diff --git a/minecraft/auth/minecraft.go b/minecraft/auth/minecraft.go index 42961290..0c7c8e56 100644 --- a/minecraft/auth/minecraft.go +++ b/minecraft/auth/minecraft.go @@ -36,7 +36,7 @@ func RequestMinecraftChain(ctx context.Context, token *XBLToken, key *ecdsa.Priv c := &http.Client{} resp, err := c.Do(request) if err != nil { - return "", fmt.Errorf("POST %v: %v", minecraftAuthURL, err) + return "", fmt.Errorf("POST %v: %w", minecraftAuthURL, err) } if resp.StatusCode != 200 { return "", fmt.Errorf("POST %v: %v", minecraftAuthURL, resp.Status) diff --git a/minecraft/auth/xbox.go b/minecraft/auth/xbox.go index 8cfaca29..9eb87aac 100644 --- a/minecraft/auth/xbox.go +++ b/minecraft/auth/xbox.go @@ -87,7 +87,7 @@ func obtainXBLToken(ctx context.Context, c *http.Client, key *ecdsa.PrivateKey, resp, err := c.Do(req) if err != nil { - return nil, fmt.Errorf("POST %v: %v", "https://sisu.xboxlive.com/authorize", err) + return nil, fmt.Errorf("POST %v: %w", "https://sisu.xboxlive.com/authorize", err) } defer func() { _ = resp.Body.Close() @@ -132,7 +132,7 @@ func obtainDeviceToken(ctx context.Context, c *http.Client, key *ecdsa.PrivateKe resp, err := c.Do(request) if err != nil { - return nil, fmt.Errorf("POST %v: %v", "https://device.auth.xboxlive.com/device/authenticate", err) + return nil, fmt.Errorf("POST %v: %w", "https://device.auth.xboxlive.com/device/authenticate", err) } defer func() { _ = resp.Body.Close() diff --git a/minecraft/conn.go b/minecraft/conn.go index 50245474..748c28f9 100644 --- a/minecraft/conn.go +++ b/minecraft/conn.go @@ -442,7 +442,7 @@ func (conn *Conn) Flush() error { if len(conn.bufferedSend) > 0 { if err := conn.enc.Encode(conn.bufferedSend); err != nil && !errors.Is(err, net.ErrClosed) { // Should never happen. - panic(fmt.Errorf("error encoding packet batch: %v", err)) + panic(fmt.Errorf("error encoding packet batch: %w", err)) } // First manually clear out conn.bufferedSend so that re-using the slice after resetting its length to // 0 doesn't result in an 'invisible' memory leak. @@ -612,7 +612,7 @@ func (conn *Conn) handleMultiple(pks []packet.Packet) error { var err error for _, pk := range pks { if e := conn.handlePacket(pk); e != nil { - err = e + err = fmt.Errorf("handle %T: %w", pk, e) } } return err @@ -685,7 +685,7 @@ func (conn *Conn) handleRequestNetworkSettings(pk *packet.RequestNetworkSettings status = packet.PlayStatusLoginFailedServer } _ = conn.WritePacket(&packet.PlayStatus{Status: status}) - return fmt.Errorf("%v connected with an incompatible protocol: expected protocol = %v, client protocol = %v", conn.identityData.DisplayName, protocol.CurrentProtocol, pk.ClientProtocol) + return fmt.Errorf("incompatible protocol version: expected %v, got %v", protocol.CurrentProtocol, pk.ClientProtocol) } conn.expect(packet.IDLogin) @@ -693,7 +693,7 @@ func (conn *Conn) handleRequestNetworkSettings(pk *packet.RequestNetworkSettings CompressionThreshold: 512, CompressionAlgorithm: conn.compression.EncodeCompression(), }); err != nil { - return fmt.Errorf("error sending network settings: %v", err) + return fmt.Errorf("send NetworkSettings: %w", err) } _ = conn.Flush() conn.enc.EnableCompression(conn.compression) @@ -705,7 +705,7 @@ func (conn *Conn) handleRequestNetworkSettings(pk *packet.RequestNetworkSettings func (conn *Conn) handleNetworkSettings(pk *packet.NetworkSettings) error { alg, ok := packet.CompressionByID(pk.CompressionAlgorithm) if !ok { - return fmt.Errorf("unknown compression algorithm: %v", pk.CompressionAlgorithm) + return fmt.Errorf("unknown compression algorithm %v", pk.CompressionAlgorithm) } conn.enc.EnableCompression(alg) conn.dec.EnableCompression() @@ -730,10 +730,10 @@ func (conn *Conn) handleLogin(pk *packet.Login) error { // Make sure the player is logged in with XBOX Live when necessary. if !authResult.XBOXLiveAuthenticated && conn.authEnabled { _ = conn.WritePacket(&packet.Disconnect{Message: text.Colourf("You must be logged in with XBOX Live to join.")}) - return fmt.Errorf("connection %v was not authenticated to XBOX Live", conn.RemoteAddr()) + return fmt.Errorf("client was not authenticated to XBOX Live") } if err := conn.enableEncryption(authResult.PublicKey); err != nil { - return fmt.Errorf("error enabling encryption: %v", err) + return fmt.Errorf("enable encryption: %w", err) } return nil } @@ -743,7 +743,7 @@ func (conn *Conn) handleClientToServerHandshake() error { // The next expected packet is a resource pack client response. conn.expect(packet.IDResourcePackClientResponse, packet.IDClientCacheStatus) if err := conn.WritePacket(&packet.PlayStatus{Status: packet.PlayStatusLoginSuccess}); err != nil { - return fmt.Errorf("error sending play status login success: %v", err) + return fmt.Errorf("send PlayStatus (Status=LoginSuccess): %w", err) } pk := &packet.ResourcePacksInfo{TexturePackRequired: conn.texturePacksRequired} for _, pack := range conn.resourcePacks { @@ -775,7 +775,7 @@ func (conn *Conn) handleClientToServerHandshake() error { } // Finally we send the packet after the play status. if err := conn.WritePacket(pk); err != nil { - return fmt.Errorf("error sending resource packs info: %v", err) + return fmt.Errorf("send ResourcePacksInfo: %w", err) } return nil } @@ -809,7 +809,7 @@ func (conn *Conn) handleServerToClientHandshake(pk *packet.ServerToClientHandsha c.Salt = strings.TrimRight(c.Salt, "=") salt, err := base64.RawStdEncoding.DecodeString(c.Salt) if err != nil { - return fmt.Errorf("error base64 decoding ServerToClientHandshake salt: %v", err) + return fmt.Errorf("decode ServerToClientHandshake salt: %w", err) } x, _ := pub.Curve.ScalarMult(pub.X, pub.Y, conn.privateKey.D.Bytes()) @@ -849,7 +849,7 @@ func (conn *Conn) handleResourcePacksInfo(pk *packet.ResourcePacksInfo) error { for index, pack := range pk.TexturePacks { if _, ok := conn.packQueue.downloadingPacks[pack.UUID]; ok { - conn.log.Printf("duplicate texture pack entry %v in resource pack info\n", pack.UUID) + conn.log.Printf("handle ResourcePacksInfo: duplicate texture pack (UUID=%v)\n", pack.UUID) conn.packQueue.packAmount-- continue } @@ -872,7 +872,7 @@ func (conn *Conn) handleResourcePacksInfo(pk *packet.ResourcePacksInfo) error { } for index, pack := range pk.BehaviourPacks { if _, ok := conn.packQueue.downloadingPacks[pack.UUID]; ok { - conn.log.Printf("duplicate behaviour pack entry %v in resource pack info\n", pack.UUID) + conn.log.Printf("handle ResourcePacksInfo: duplicate behaviour pack (UUID=%v)\n", pack.UUID) conn.packQueue.packAmount-- continue } @@ -918,17 +918,17 @@ func (conn *Conn) handleResourcePackStack(pk *packet.ResourcePackStack) error { if pack.UUID == behaviourPack.UUID { // We had a behaviour pack with the same UUID as the texture pack, so we drop the texture // pack and log it. - conn.log.Printf("dropping behaviour pack with UUID %v due to a texture pack with the same UUID\n", pack.UUID) + conn.log.Printf("handle ResourcePackStack: dropping behaviour pack (UUID=%v) due to a texture pack with the same UUID\n", pack.UUID) pk.BehaviourPacks = append(pk.BehaviourPacks[:i], pk.BehaviourPacks[i+1:]...) } } if !conn.hasPack(pack.UUID, pack.Version, false) { - return fmt.Errorf("texture pack {uuid=%v, version=%v} not downloaded", pack.UUID, pack.Version) + return fmt.Errorf("texture pack (UUID=%v, version=%v) not downloaded", pack.UUID, pack.Version) } } for _, pack := range pk.BehaviourPacks { if !conn.hasPack(pack.UUID, pack.Version, true) { - return fmt.Errorf("behaviour pack {uuid=%v, version=%v} not downloaded", pack.UUID, pack.Version) + return fmt.Errorf("behaviour pack (UUID=%v, version=%v) not downloaded", pack.UUID, pack.Version) } } conn.expect(packet.IDStartGame) @@ -977,7 +977,7 @@ func (conn *Conn) handleResourcePackClientResponse(pk *packet.ResourcePackClient packs := pk.PacksToDownload conn.packQueue = &resourcePackQueue{packs: conn.resourcePacks} if err := conn.packQueue.Request(packs); err != nil { - return fmt.Errorf("error looking up resource packs to download: %v", err) + return fmt.Errorf("lookup resource packs by UUID: %w", err) } // Proceed with the first resource pack download. We run all downloads in sequence rather than in // parallel, as it's less prone to packet loss. @@ -1003,12 +1003,12 @@ func (conn *Conn) handleResourcePackClientResponse(pk *packet.ResourcePackClient }) } if err := conn.WritePacket(pk); err != nil { - return fmt.Errorf("error writing resource pack stack packet: %v", err) + return fmt.Errorf("send ResourcePackStack: %w", err) } case packet.PackResponseCompleted: conn.loggedIn = true default: - return fmt.Errorf("unknown resource pack client response: %v", pk.Response) + return fmt.Errorf("unknown ResourcePackClientResponse response type %v", pk.Response) } return nil } @@ -1069,7 +1069,7 @@ func (conn *Conn) nextResourcePackDownload() error { return fmt.Errorf("no resource packs to download") } if err := conn.WritePacket(pk); err != nil { - return fmt.Errorf("error sending resource pack data info packet: %v", err) + return fmt.Errorf("send ResourcePackDataInfo: %w", err) } // Set the next expected packet to ResourcePackChunkRequest packets. conn.expect(packet.IDResourcePackChunkRequest) @@ -1085,12 +1085,12 @@ func (conn *Conn) handleResourcePackDataInfo(pk *packet.ResourcePackDataInfo) er if !ok { // We either already downloaded the pack or we got sent an invalid UUID, that did not match any pack // sent in the ResourcePacksInfo packet. - return fmt.Errorf("unknown pack to download with UUID %v", id) + return fmt.Errorf("unknown pack (UUID=%v)", id) } if pack.size != pk.Size { // Size mismatch: The ResourcePacksInfo packet had a size for the pack that did not match with the // size sent here. - conn.log.Printf("pack %v had a different size in the ResourcePacksInfo packet than the ResourcePackDataInfo packet\n", id) + conn.log.Printf("pack (UUID=%v) had a different size in ResourcePacksInfo than in ResourcePackDataInfo\n", id) pack.size = pk.Size } @@ -1126,13 +1126,13 @@ func (conn *Conn) handleResourcePackDataInfo(pk *packet.ResourcePackDataInfo) er defer conn.packMu.Unlock() if pack.buf.Len() != int(pack.size) { - conn.log.Printf("incorrect resource pack size: expected %v, but got %v\n", pack.size, pack.buf.Len()) + conn.log.Printf("incorrect resource pack size (UUID=%v): expected %v, got %v\n", id, pack.size, pack.buf.Len()) return } // First parse the resource pack from the total byte buffer we obtained. newPack, err := resource.Read(pack.buf) if err != nil { - conn.log.Printf("invalid full resource pack data for UUID %v: %v\n", id, err) + conn.log.Printf("invalid full resource pack data (UUID=%v): %v\n", id, err) return } conn.packQueue.packAmount-- @@ -1154,16 +1154,16 @@ func (conn *Conn) handleResourcePackChunkData(pk *packet.ResourcePackChunkData) if !ok { // We haven't received a ResourcePackDataInfo packet from the server, so we can't use this data to // download a resource pack. - return fmt.Errorf("resource pack chunk data for resource pack that was not being downloaded") + return fmt.Errorf("chunk data for resource pack that was not being downloaded") } lastData := pack.buf.Len()+int(pack.chunkSize) >= int(pack.size) if !lastData && uint32(len(pk.Data)) != pack.chunkSize { // The chunk data didn't have the full size and wasn't the last data to be sent for the resource pack, // meaning we got too little data. - return fmt.Errorf("resource pack chunk data had a length of %v, but expected %v", len(pk.Data), pack.chunkSize) + return fmt.Errorf("expected chunk size %v, got %v", pack.chunkSize, len(pk.Data)) } if pk.ChunkIndex != pack.expectedIndex { - return fmt.Errorf("resource pack chunk data had chunk index %v, but expected %v", pk.ChunkIndex, pack.expectedIndex) + return fmt.Errorf("expected chunk index %v, got %v", pack.expectedIndex, pk.ChunkIndex) } pack.expectedIndex++ pack.newFrag <- pk.Data @@ -1175,10 +1175,10 @@ func (conn *Conn) handleResourcePackChunkData(pk *packet.ResourcePackChunkData) func (conn *Conn) handleResourcePackChunkRequest(pk *packet.ResourcePackChunkRequest) error { current := conn.packQueue.currentPack if current.UUID() != pk.UUID { - return fmt.Errorf("resource pack chunk request had unexpected UUID: expected %v, but got %v", current.UUID(), pk.UUID) + return fmt.Errorf("expected pack UUID %v, but got %v", current.UUID(), pk.UUID) } if conn.packQueue.currentOffset != uint64(pk.ChunkIndex)*packChunkSize { - return fmt.Errorf("resource pack chunk request had unexpected chunk index: expected %v, but got %v", conn.packQueue.currentOffset/packChunkSize, pk.ChunkIndex) + return fmt.Errorf("expected pack UUID %v, but got %v", conn.packQueue.currentOffset/packChunkSize, pk.ChunkIndex) } response := &packet.ResourcePackChunkData{ UUID: pk.UUID, @@ -1192,7 +1192,7 @@ func (conn *Conn) handleResourcePackChunkRequest(pk *packet.ResourcePackChunkReq // If we hit an EOF, we don't need to return an error, as we've simply reached the end of the content // AKA the last chunk. if err != io.EOF { - return fmt.Errorf("error reading resource pack chunk: %v", err) + return fmt.Errorf("read resource pack chunk: %w", err) } response.Data = response.Data[:n] @@ -1205,7 +1205,7 @@ func (conn *Conn) handleResourcePackChunkRequest(pk *packet.ResourcePackChunkReq }() } if err := conn.WritePacket(response); err != nil { - return fmt.Errorf("error writing resource pack chunk data packet: %v", err) + return fmt.Errorf("send ResourcePackChunkData: %w", err) } return nil @@ -1263,7 +1263,7 @@ func (conn *Conn) handleStartGame(pk *packet.StartGame) error { // of the connection, and spawns the player. func (conn *Conn) handleRequestChunkRadius(pk *packet.RequestChunkRadius) error { if pk.ChunkRadius < 1 { - return fmt.Errorf("requested chunk radius must be at least 1, got %v", pk.ChunkRadius) + return fmt.Errorf("expected chunk radius of at least 1, got %v", pk.ChunkRadius) } conn.expect(packet.IDSetLocalPlayerAsInitialised) radius := pk.ChunkRadius @@ -1295,7 +1295,7 @@ func (conn *Conn) handleRequestChunkRadius(pk *packet.RequestChunkRadius) error // radius of the connection. func (conn *Conn) handleChunkRadiusUpdated(pk *packet.ChunkRadiusUpdated) error { if pk.ChunkRadius < 1 { - return fmt.Errorf("new chunk radius must be at least 1, got %v", pk.ChunkRadius) + return fmt.Errorf("expected chunk radius of at least 1, got %v", pk.ChunkRadius) } conn.expect(packet.IDPlayStatus) @@ -1311,7 +1311,7 @@ func (conn *Conn) handleChunkRadiusUpdated(pk *packet.ChunkRadiusUpdated) error // logged in. func (conn *Conn) handleSetLocalPlayerAsInitialised(pk *packet.SetLocalPlayerAsInitialised) error { if pk.EntityRuntimeID != conn.gameData.EntityRuntimeID { - return fmt.Errorf("entity runtime ID mismatch: entity runtime ID in StartGame and SetLocalPlayerAsInitialised packets should be equal") + return fmt.Errorf("entity runtime ID mismatch: expected %v (from StartGame), got %v", conn.gameData.EntityRuntimeID, pk.EntityRuntimeID) } if conn.waitingForSpawn.CompareAndSwap(true, false) { close(conn.spawn) @@ -1325,7 +1325,7 @@ func (conn *Conn) handlePlayStatus(pk *packet.PlayStatus) error { switch pk.Status { case packet.PlayStatusLoginSuccess: if err := conn.WritePacket(&packet.ClientCacheStatus{Enabled: conn.cacheEnabled}); err != nil { - return fmt.Errorf("error sending client cache status: %v", err) + return fmt.Errorf("send ClientCacheStatus: %w", err) } // The next packet we expect is the ResourcePacksInfo packet. conn.expect(packet.IDResourcePacksInfo) @@ -1360,7 +1360,7 @@ func (conn *Conn) handlePlayStatus(pk *packet.PlayStatus) error { _ = conn.Close() return fmt.Errorf("cannot join an editor game on vanilla") default: - return fmt.Errorf("unknown play status in PlayStatus packet %v", pk.Status) + return fmt.Errorf("unknown play status %v", pk.Status) } } @@ -1391,7 +1391,7 @@ func (conn *Conn) enableEncryption(clientPublicKey *ecdsa.PublicKey) error { return fmt.Errorf("compact serialise server JWT: %w", err) } if err := conn.WritePacket(&packet.ServerToClientHandshake{JWT: []byte(serverJWT)}); err != nil { - return fmt.Errorf("error sending ServerToClientHandshake packet: %v", err) + return fmt.Errorf("send ServerToClientHandshake: %w", err) } // Flush immediately as we'll enable encryption after this. _ = conn.Flush() diff --git a/minecraft/dial.go b/minecraft/dial.go index e4207d9f..95a3d123 100644 --- a/minecraft/dial.go +++ b/minecraft/dial.go @@ -169,7 +169,7 @@ func (d Dialer) DialContext(ctx context.Context, network, address string) (conn n, ok := networkByID(network) if !ok { - return nil, fmt.Errorf("listen: no network under id: %v", network) + return nil, fmt.Errorf("dial: no network under id %v", network) } var pong []byte @@ -287,14 +287,14 @@ func listenConn(conn *Conn, logger *log.Logger, l, c chan struct{}) { packets, err := conn.dec.Decode() if err != nil { if !errors.Is(err, net.ErrClosed) { - logger.Printf("error reading from dialer connection: %v\n", err) + logger.Printf("dialer conn: %v\n", err) } return } for _, data := range packets { loggedInBefore, readyToLoginBefore := conn.loggedIn, conn.readyToLogin if err := conn.receive(data); err != nil { - logger.Printf("error: %v", err) + logger.Printf("dialer conn: %v", err) return } if !readyToLoginBefore && conn.readyToLogin { @@ -317,17 +317,17 @@ func authChain(ctx context.Context, src oauth2.TokenSource, key *ecdsa.PrivateKe // Obtain the Live token, and using that the XSTS token. liveToken, err := src.Token() if err != nil { - return "", fmt.Errorf("error obtaining Live Connect token: %v", err) + return "", fmt.Errorf("request Live Connect token: %w", err) } xsts, err := auth.RequestXBLToken(ctx, liveToken, "https://multiplayer.minecraft.net/") if err != nil { - return "", fmt.Errorf("error obtaining XBOX Live token: %v", err) + return "", fmt.Errorf("request XBOX Live token: %w", err) } // Obtain the raw chain data using the chain, err := auth.RequestMinecraftChain(ctx, xsts, key) if err != nil { - return "", fmt.Errorf("error obtaining Minecraft auth chain: %v", err) + return "", fmt.Errorf("request Minecraft auth chain: %w", err) } return chain, nil } diff --git a/minecraft/listener.go b/minecraft/listener.go index bb3f78de..d5d16882 100644 --- a/minecraft/listener.go +++ b/minecraft/listener.go @@ -104,7 +104,7 @@ type Listener struct { func (cfg ListenConfig) Listen(network string, address string) (*Listener, error) { n, ok := networkByID(network) if !ok { - return nil, fmt.Errorf("listen: no network under id: %v", network) + return nil, fmt.Errorf("listen: no network under id %v", network) } netListener, err := n.Listen(address) @@ -276,14 +276,14 @@ func (listener *Listener) handleConn(conn *Conn) { packets, err := conn.dec.Decode() if err != nil { if !errors.Is(err, net.ErrClosed) { - listener.cfg.ErrorLog.Printf("error reading from listener connection: %v\n", err) + conn.log.Printf("listener conn: %v\n", err) } return } for _, data := range packets { loggedInBefore := conn.loggedIn if err := conn.receive(data); err != nil { - listener.cfg.ErrorLog.Printf("error: %v", err) + conn.log.Printf("listener conn: %v", err) return } if !loggedInBefore && conn.loggedIn { diff --git a/minecraft/nbt/dump.go b/minecraft/nbt/dump.go index b59172b0..fc9c615c 100644 --- a/minecraft/nbt/dump.go +++ b/minecraft/nbt/dump.go @@ -19,7 +19,7 @@ import ( func Dump(data []byte, encoding Encoding) (string, error) { var m map[string]any if err := UnmarshalEncoding(data, &m, encoding); err != nil { - return "", fmt.Errorf("error decoding NBT: %v", err) + return "", fmt.Errorf("decode NBT: %w", err) } s := &dumpState{} return s.encodeTagType(m) + "(" + s.encodeTagValue(m) + ")", nil diff --git a/minecraft/packet.go b/minecraft/packet.go index c9d5aca9..70266417 100644 --- a/minecraft/packet.go +++ b/minecraft/packet.go @@ -2,6 +2,7 @@ package minecraft import ( "bytes" + "errors" "fmt" "github.com/sandertv/gophertunnel/minecraft/protocol/packet" ) @@ -20,7 +21,7 @@ func parseData(data []byte, conn *Conn) (*packetData, error) { if err := header.Read(buf); err != nil { // We don't return this as an error as it's not in the hand of the user to control this. Instead, // we return to reading a new packet. - return nil, fmt.Errorf("error reading packet header: %v", err) + return nil, fmt.Errorf("read packet header: %w", err) } if conn.packetFunc != nil { // The packet func was set, so we call it. @@ -34,19 +35,19 @@ type unknownPacketError struct { } func (err unknownPacketError) Error() string { - return fmt.Sprintf("unexpected packet with ID %v", err.id) + return fmt.Sprintf("unexpected packet (ID=%v)", err.id) } // decode decodes the packet payload held in the packetData and returns the packet.Packet decoded. func (p *packetData) decode(conn *Conn) (pks []packet.Packet, err error) { defer func() { if recoveredErr := recover(); recoveredErr != nil { - err = fmt.Errorf("packet %v: %w", p.h.PacketID, recoveredErr.(error)) + err = fmt.Errorf("decode packet %v: %w", p.h.PacketID, recoveredErr.(error)) } if err == nil { return } - if _, ok := err.(unknownPacketError); ok || conn.disconnectOnInvalidPacket { + if ok := errors.As(err, &unknownPacketError{}); ok || conn.disconnectOnInvalidPacket { _ = conn.Close() } }() @@ -67,7 +68,7 @@ func (p *packetData) decode(conn *Conn) (pks []packet.Packet, err error) { r := conn.proto.NewReader(p.payload, conn.shieldID.Load(), conn.readerLimits) pk.Marshal(r) if p.payload.Len() != 0 { - err = fmt.Errorf("%T: %v unread bytes left: 0x%x", pk, p.payload.Len(), p.payload.Bytes()) + err = fmt.Errorf("decode packet %T: %v unread bytes left: 0x%x", pk, p.payload.Len(), p.payload.Bytes()) } if conn.disconnectOnInvalidPacket && err != nil { return nil, err diff --git a/minecraft/protocol/login/data.go b/minecraft/protocol/login/data.go index 4156036b..dcb8d6de 100644 --- a/minecraft/protocol/login/data.go +++ b/minecraft/protocol/login/data.go @@ -294,34 +294,34 @@ func (data ClientData) Validate() error { return fmt.Errorf("ServerAddress must be resolveable as a UDP address, but got %v", data.ServerAddress) } if err := base64DecLength(data.SkinData, data.SkinImageHeight*data.SkinImageWidth*4); err != nil { - return fmt.Errorf("SkinData is invalid: %v", err) + return fmt.Errorf("SkinData is invalid: %w", err) } if err := base64DecLength(data.CapeData, data.CapeImageHeight*data.CapeImageWidth*4); err != nil { - return fmt.Errorf("CapeData is invalid: %v", err) + return fmt.Errorf("CapeData is invalid: %w", err) } for _, anim := range data.AnimatedImageData { if err := base64DecLength(anim.Image, anim.ImageHeight*anim.ImageWidth*4); err != nil { - return fmt.Errorf("invalid animated image data: %v", err) + return fmt.Errorf("invalid animated image data: %w", err) } if anim.Type < 0 || anim.Type > 3 { return fmt.Errorf("invalid animation type: %v", anim.Type) } } if geomData, err := base64.StdEncoding.DecodeString(data.SkinGeometry); err != nil { - return fmt.Errorf("SkinGeometry was not a valid base64 string: %v", err) + return fmt.Errorf("SkinGeometry was not a valid base64 string: %w", err) } else if len(geomData) != 0 { m := make(map[string]any) if err := json.Unmarshal(geomData, &m); err != nil { - return fmt.Errorf("SkinGeometry base64 decoded was not a valid JSON string: %v", err) + return fmt.Errorf("SkinGeometry base64 decoded was not a valid JSON string: %w", err) } } b, err := base64.StdEncoding.DecodeString(data.SkinResourcePatch) if err != nil { - return fmt.Errorf("SkinResourcePatch was not a valid base64 string: %v", err) + return fmt.Errorf("SkinResourcePatch was not a valid base64 string: %w", err) } m := make(map[string]any) if err := json.Unmarshal(b, &m); err != nil { - return fmt.Errorf("SkinResourcePatch base64 decoded was not a valid JSON string: %v", err) + return fmt.Errorf("SkinResourcePatch base64 decoded was not a valid JSON string: %w", err) } if data.SkinID == "" { return fmt.Errorf("SkinID must not be an empty string") @@ -337,7 +337,7 @@ func (data ClientData) Validate() error { func base64DecLength(base64Data string, validLengths ...int) error { data, err := base64.StdEncoding.DecodeString(base64Data) if err != nil { - return fmt.Errorf("error decoding base64 data: %v", err) + return fmt.Errorf("decode base64 data: %w", err) } actualLength := len(data) for _, length := range validLengths { @@ -345,5 +345,5 @@ func base64DecLength(base64Data string, validLengths ...int) error { return nil } } - return fmt.Errorf("invalid size: got %v, but expected one of %v", actualLength, validLengths) + return fmt.Errorf("invalid size: got %v, expected one of %v", actualLength, validLengths) } diff --git a/minecraft/protocol/login/request.go b/minecraft/protocol/login/request.go index c0cf70af..190e725f 100644 --- a/minecraft/protocol/login/request.go +++ b/minecraft/protocol/login/request.go @@ -149,7 +149,7 @@ func parseLoginRequest(requestData []byte) (*request, error) { } var rawLength int32 if err := binary.Read(buf, binary.LittleEndian, &rawLength); err != nil { - return nil, fmt.Errorf("error reading raw token length: %v", err) + return nil, fmt.Errorf("read raw token length: %w", err) } return &request{Chain: chain, RawToken: string(buf.Next(int(rawLength)))}, nil } @@ -269,17 +269,17 @@ func EncodeOffline(identityData IdentityData, data ClientData, key *ecdsa.Privat func decodeChain(buf *bytes.Buffer) (chain, error) { var chainLength int32 if err := binary.Read(buf, binary.LittleEndian, &chainLength); err != nil { - return nil, fmt.Errorf("error reading chain length: %v", err) + return nil, fmt.Errorf("read chain length: %w", err) } chainData := buf.Next(int(chainLength)) request := &request{} if err := json.Unmarshal(chainData, request); err != nil { - return nil, fmt.Errorf("error decoding request chain JSON: %v", err) + return nil, fmt.Errorf("decode chain JSON: %w", err) } // First check if the chain actually has any elements in it. if len(request.Chain) == 0 { - return nil, fmt.Errorf("connection request had no claims in the chain") + return nil, fmt.Errorf("decode chain: no elements") } return request.Chain, nil } @@ -318,15 +318,15 @@ type identityPublicKeyClaims struct { func ParsePublicKey(b64Data string, key *ecdsa.PublicKey) error { data, err := base64.StdEncoding.DecodeString(b64Data) if err != nil { - return fmt.Errorf("error base64 decoding public key data: %v", err) + return fmt.Errorf("decode public key data: %w", err) } publicKey, err := x509.ParsePKIXPublicKey(data) if err != nil { - return fmt.Errorf("error parsing public key: %v", err) + return fmt.Errorf("parse public key: %w", err) } ecdsaKey, ok := publicKey.(*ecdsa.PublicKey) if !ok { - return fmt.Errorf("expected ECDSA public key, but got %v", key) + return fmt.Errorf("expected ECDSA public key, got %v", key) } *key = *ecdsaKey return nil diff --git a/minecraft/protocol/packet/compression.go b/minecraft/protocol/packet/compression.go index 77b23e4c..22737bd9 100644 --- a/minecraft/protocol/packet/compression.go +++ b/minecraft/protocol/packet/compression.go @@ -96,7 +96,7 @@ func (flateCompression) Decompress(compressed []byte) ([]byte, error) { // Guess an uncompressed size of 2*len(compressed). decompressed := bytes.NewBuffer(make([]byte, 0, len(compressed)*2)) if _, err := io.Copy(decompressed, c); err != nil { - return nil, fmt.Errorf("decompress flate: %v", err) + return nil, fmt.Errorf("decompress flate: %w", err) } return decompressed.Bytes(), nil } diff --git a/minecraft/protocol/packet/decoder.go b/minecraft/protocol/packet/decoder.go index 458a93c9..44047a02 100644 --- a/minecraft/protocol/packet/decoder.go +++ b/minecraft/protocol/packet/decoder.go @@ -86,20 +86,20 @@ func (decoder *Decoder) Decode() (packets [][]byte, err error) { data, err = decoder.pr.ReadPacket() } if err != nil { - return nil, fmt.Errorf("error reading batch from reader: %v", err) + return nil, fmt.Errorf("read batch: %w", err) } if len(data) == 0 { return nil, nil } if data[0] != header { - return nil, fmt.Errorf("error reading packet: invalid packet header %x: expected %x", data[0], header) + return nil, fmt.Errorf("decode batch: invalid header %x, expected %x", data[0], header) } data = data[1:] if decoder.encrypt != nil { decoder.encrypt.decrypt(data) if err := decoder.encrypt.verify(data); err != nil { // The packet did not have a correct checksum. - return nil, fmt.Errorf("error verifying packet: %v", err) + return nil, fmt.Errorf("verify batch: %w", err) } data = data[:len(data)-8] } @@ -110,11 +110,11 @@ func (decoder *Decoder) Decode() (packets [][]byte, err error) { } else { compression, ok := CompressionByID(uint16(data[0])) if !ok { - return nil, fmt.Errorf("error decompressing packet: unknown compression algorithm %v", data[0]) + return nil, fmt.Errorf("decompress batch: unknown compression algorithm %v", data[0]) } data, err = compression.Decompress(data[1:]) if err != nil { - return nil, fmt.Errorf("error decompressing packet: %v", err) + return nil, fmt.Errorf("decompress batch: %w", err) } } } @@ -123,12 +123,12 @@ func (decoder *Decoder) Decode() (packets [][]byte, err error) { for b.Len() != 0 { var length uint32 if err := protocol.Varuint32(b, &length); err != nil { - return nil, fmt.Errorf("error reading packet length: %v", err) + return nil, fmt.Errorf("decode batch: read packet length: %w", err) } packets = append(packets, b.Next(int(length))) } if len(packets) > maximumInBatch && decoder.checkPacketLimit { - return nil, fmt.Errorf("number of packets %v in compressed batch exceeds %v", len(packets), maximumInBatch) + return nil, fmt.Errorf("decode batch: number of packets %v exceeds max=%v", len(packets), maximumInBatch) } return packets, nil } diff --git a/minecraft/protocol/packet/encoder.go b/minecraft/protocol/packet/encoder.go index 16e7cbba..f3ccef8a 100644 --- a/minecraft/protocol/packet/encoder.go +++ b/minecraft/protocol/packet/encoder.go @@ -21,9 +21,7 @@ type Encoder struct { // NewEncoder returns a new Encoder for the io.Writer passed. Each final packet produced by the Encoder is // sent with a single call to io.Writer.Write(). func NewEncoder(w io.Writer) *Encoder { - return &Encoder{ - w: w, - } + return &Encoder{w: w} } // EnableEncryption enables encryption for the Encoder using the secret key bytes passed. Each packet sent @@ -54,10 +52,10 @@ func (encoder *Encoder) Encode(packets [][]byte) error { for _, packet := range packets { // Each packet is prefixed with a varuint32 specifying the length of the packet. if err := writeVaruint32(buf, uint32(len(packet)), l); err != nil { - return fmt.Errorf("error writing varuint32 length: %v", err) + return fmt.Errorf("encode batch: write packet length: %w", err) } if _, err := buf.Write(packet); err != nil { - return fmt.Errorf("error writing packet payload: %v", err) + return fmt.Errorf("encode batch: write packet payload: %w", err) } } @@ -68,7 +66,7 @@ func (encoder *Encoder) Encode(packets [][]byte) error { var err error data, err = encoder.compression.Compress(data) if err != nil { - return fmt.Errorf("error compressing packet: %v", err) + return fmt.Errorf("compress batch: %w", err) } } @@ -79,7 +77,7 @@ func (encoder *Encoder) Encode(packets [][]byte) error { data = encoder.encrypt.encrypt(data) } if _, err := encoder.w.Write(data); err != nil { - return fmt.Errorf("error writing compressed packet to io.Writer: %v", err) + return fmt.Errorf("write batch: %w", err) } return nil } @@ -87,12 +85,7 @@ func (encoder *Encoder) Encode(packets [][]byte) error { // writeVaruint32 writes a uint32 to the destination buffer passed with a size of 1-5 bytes. It uses byte // slice b in order to prevent allocations. func writeVaruint32(dst io.Writer, x uint32, b []byte) error { - b[4] = 0 - b[3] = 0 - b[2] = 0 - b[1] = 0 - b[0] = 0 - + clear(b[:5]) i := 0 for x >= 0x80 { b[i] = byte(x) | 0x80 diff --git a/minecraft/protocol/packet/encryption.go b/minecraft/protocol/packet/encryption.go index e51eaea5..af25ee21 100644 --- a/minecraft/protocol/packet/encryption.go +++ b/minecraft/protocol/packet/encryption.go @@ -70,7 +70,7 @@ func (encrypt *encrypt) verify(data []byte) error { // Finally we check if the original sum was equal to the sum we just produced. if !bytes.Equal(sum, ourSum) { - return fmt.Errorf("invalid checksum of packet %v (%x): %x should be %x", encrypt.sendCounter-1, data, sum, ourSum) + return fmt.Errorf("invalid checksum of packet %v: expected %x, got %x", encrypt.sendCounter-1, ourSum, sum) } return nil } diff --git a/minecraft/resource/pack.go b/minecraft/resource/pack.go index cc32b6fb..9f45d193 100644 --- a/minecraft/resource/pack.go +++ b/minecraft/resource/pack.go @@ -51,11 +51,11 @@ func ReadPath(path string) (*Pack, error) { func ReadURL(url string) (*Pack, error) { resp, err := http.Get(url) if err != nil { - return nil, fmt.Errorf("error downloading resource pack: %v", err) + return nil, fmt.Errorf("download resource pack: %w", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { - return nil, fmt.Errorf("error downloading resource pack: %v (%d)", resp.Status, resp.StatusCode) + return nil, fmt.Errorf("download resource pack: %v (%d)", resp.Status, resp.StatusCode) } pack, err := Read(resp.Body) if err != nil { @@ -97,15 +97,15 @@ func MustReadURL(url string) *Pack { func Read(r io.Reader) (*Pack, error) { temp, err := createTempFile() if err != nil { - return nil, fmt.Errorf("error creating temp zip archive: %v", err) + return nil, fmt.Errorf("create temp zip archive: %w", err) } _, _ = io.Copy(temp, r) if err := temp.Close(); err != nil { - return nil, fmt.Errorf("error closing temp zip archive: %v", err) + return nil, fmt.Errorf("close temp zip archive: %w", err) } pack, parseErr := ReadPath(temp.Name()) if err := os.Remove(temp.Name()); err != nil { - return nil, fmt.Errorf("error removing temp zip archive: %v", err) + return nil, fmt.Errorf("remove temp zip archive: %w", err) } return pack, parseErr } @@ -252,7 +252,7 @@ func (pack *Pack) String() string { func compile(path string) (*Pack, error) { info, err := os.Stat(path) if err != nil { - return nil, fmt.Errorf("error opening resource pack path: %v", err) + return nil, fmt.Errorf("open resource pack path: %w", err) } if info.IsDir() { temp, err := createTempArchive(path) @@ -272,14 +272,14 @@ func compile(path string) (*Pack, error) { // First we read the manifest to ensure that it exists and is valid. manifest, err := readManifest(path) if err != nil { - return nil, fmt.Errorf("error reading manifest: %v", err) + return nil, fmt.Errorf("read manifest: %w", err) } // Then we read the entire content of the zip archive into a byte slice and compute the SHA256 checksum // and a reader. content, err := os.ReadFile(path) if err != nil { - return nil, fmt.Errorf("error reading resource pack file content: %v", err) + return nil, fmt.Errorf("read resource pack file content: %w", err) } checksum := sha256.Sum256(content) contentReader := bytes.NewReader(content) @@ -301,7 +301,7 @@ func createTempArchive(path string) (*os.File, error) { } relPath, err := filepath.Rel(path, filePath) if err != nil { - return fmt.Errorf("error finding relative path: %v", err) + return fmt.Errorf("find relative path: %w", err) } // Make sure to replace backslashes with forward slashes as Go zip only allows that. relPath = strings.Replace(relPath, `\`, "/", -1) @@ -311,7 +311,7 @@ func createTempArchive(path string) (*os.File, error) { } s, err := os.Stat(filePath) if err != nil { - return fmt.Errorf("error getting stat of file path %v: %w", filePath, err) + return fmt.Errorf("read stat of file path %v: %w", filePath, err) } if s.IsDir() { // This is a directory: Go zip requires you add forward slashes at the end to create directories. @@ -320,21 +320,21 @@ func createTempArchive(path string) (*os.File, error) { } f, err := writer.Create(relPath) if err != nil { - return fmt.Errorf("error creating new zip file: %v", err) + return fmt.Errorf("create new zip file: %w", err) } file, err := os.Open(filePath) if err != nil { - return fmt.Errorf("error opening resource pack file %v: %v", filePath, err) + return fmt.Errorf("open resource pack file %v: %w", filePath, err) } data, _ := io.ReadAll(file) // Write the original content into the 'zip file' so that we write compressed data to the file. if _, err := f.Write(data); err != nil { - return fmt.Errorf("error writing file data to zip: %v", err) + return fmt.Errorf("write file data to zip: %w", err) } _ = file.Close() return nil }); err != nil { - return nil, fmt.Errorf("error building zip archive: %v", err) + return nil, fmt.Errorf("build zip archive: %w", err) } _ = writer.Close() return temp, nil @@ -354,7 +354,7 @@ func createTempFile() (*os.File, error) { temp, err := os.CreateTemp(dir, "temp_resource_pack-*.mcpack") if err != nil { - return nil, fmt.Errorf("error creating temp resource pack file: %v", err) + return nil, fmt.Errorf("create temp resource pack file: %w", err) } return temp, nil } @@ -374,11 +374,11 @@ func (reader packReader) find(fileName string) (io.ReadCloser, error) { } fileReader, err := file.Open() if err != nil { - return nil, fmt.Errorf("error opening zip file %v: %v", file.Name, err) + return nil, fmt.Errorf("open zip file %v: %w", file.Name, err) } return fileReader, nil } - return nil, fmt.Errorf("could not find '%v' in zip", fileName) + return nil, fmt.Errorf("'%v' not found in zip", fileName) } // readManifest reads the manifest from the resource pack located at the path passed. If not found in the root @@ -386,7 +386,7 @@ func (reader packReader) find(fileName string) (io.ReadCloser, error) { func readManifest(path string) (*Manifest, error) { r, err := zip.OpenReader(path) if err != nil { - return nil, fmt.Errorf("error opening zip reader: %v", err) + return nil, fmt.Errorf("open zip reader: %w", err) } reader := packReader{ReadCloser: r} defer func() { @@ -396,7 +396,7 @@ func readManifest(path string) (*Manifest, error) { // Try to find the manifest file in the zip. manifestFile, err := reader.find("manifest.json") if err != nil { - return nil, fmt.Errorf("error loading manifest: %v", err) + return nil, fmt.Errorf("load manifest: %w", err) } defer func() { _ = manifestFile.Close() @@ -405,11 +405,11 @@ func readManifest(path string) (*Manifest, error) { // Read all data from the manifest file so that we can decode it into a Manifest struct. allData, err := io.ReadAll(manifestFile) if err != nil { - return nil, fmt.Errorf("error reading from manifest file: %v", err) + return nil, fmt.Errorf("read manifest file: %w", err) } manifest := &Manifest{} if err := jsonc.Unmarshal(allData, manifest); err != nil { - return nil, fmt.Errorf("error decoding manifest JSON: %v (data: %v)", err, string(allData)) + return nil, fmt.Errorf("decode manifest JSON: %w (data: %v)", err, string(allData)) } manifest.Header.UUID = strings.ToLower(manifest.Header.UUID) diff --git a/minecraft/resource_pack_queue.go b/minecraft/resource_pack_queue.go index 39480ac4..b7fdf387 100644 --- a/minecraft/resource_pack_queue.go +++ b/minecraft/resource_pack_queue.go @@ -46,7 +46,7 @@ func (queue *resourcePackQueue) Request(packs []string) error { } } if !found { - return fmt.Errorf("could not find resource pack %v", packUUID) + return fmt.Errorf("resource pack (UUID=%v) not found", packUUID) } } return nil diff --git a/minecraft/server_status_provider.go b/minecraft/server_status_provider.go index ec6bab8a..2d785592 100644 --- a/minecraft/server_status_provider.go +++ b/minecraft/server_status_provider.go @@ -118,22 +118,16 @@ func (f *ForeignStatusProvider) update() { func parsePongData(pong []byte) ServerStatus { frag := splitPong(string(pong)) if len(frag) < 7 { - return ServerStatus{ - ServerName: "Invalid pong data", - } + return ServerStatus{ServerName: "Invalid pong data"} } serverName := frag[1] online, err := strconv.Atoi(frag[4]) if err != nil { - return ServerStatus{ - ServerName: "Invalid player count", - } + return ServerStatus{ServerName: "Invalid player count"} } max, err := strconv.Atoi(frag[5]) if err != nil { - return ServerStatus{ - ServerName: "Invalid max player count", - } + return ServerStatus{ServerName: "Invalid max player count"} } return ServerStatus{ ServerName: serverName, diff --git a/query/packet.go b/query/packet.go index f9d3db89..e04c7048 100644 --- a/query/packet.go +++ b/query/packet.go @@ -144,7 +144,7 @@ func (pk *response) Unmarshal(r io.Reader) error { } num, err := strconv.ParseInt(string(numBytes), 10, 32) if err != nil { - return fmt.Errorf("invalid response number in handshake query response: %v", err) + return fmt.Errorf("invalid response number in handshake query response: %w", err) } pk.ResponseNumber = int32(num) case queryTypeInformation: diff --git a/query/query.go b/query/query.go index 782123af..dd81a5ce 100644 --- a/query/query.go +++ b/query/query.go @@ -16,7 +16,7 @@ import ( func Do(address string) (information map[string]string, err error) { conn, err := net.Dial("udp", address) if err != nil { - return nil, fmt.Errorf("error dialing UDP conn: %v", err) + return nil, fmt.Errorf("dial udp: %w", err) } // We set a deadline of five seconds: There is no point waiting even longer if the query isn't finished // by then.