New Upstream Release - golang-github-jackc-pgproto3

Ready changes

Summary

Merged new upstream version: 2.3.2 (was: 2.3.1).

Resulting package

Built on 2023-03-13T19:45 (took 6m10s)

The resulting binary packages can be installed (if you have the apt repository enabled) by running one of:

apt install -t fresh-releases golang-github-jackc-pgproto3-v2-dev

Lintian Result

Diff

diff --git a/README.md b/README.md
index 565b3ef..77a3170 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,12 @@
 [![](https://godoc.org/github.com/jackc/pgproto3?status.svg)](https://godoc.org/github.com/jackc/pgproto3)
 [![Build Status](https://travis-ci.org/jackc/pgproto3.svg)](https://travis-ci.org/jackc/pgproto3)
 
+---
+
+This version is used with pgx `v4`. In pgx `v5` it is part of the https://github.com/jackc/pgx repository.
+
+---
+
 # pgproto3
 
 Package pgproto3 is a encoder and decoder of the PostgreSQL wire protocol version 3.
diff --git a/authentication_gss.go b/authentication_gss.go
new file mode 100644
index 0000000..5a3f3b1
--- /dev/null
+++ b/authentication_gss.go
@@ -0,0 +1,58 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+	"github.com/jackc/pgio"
+)
+
+type AuthenticationGSS struct{}
+
+func (a *AuthenticationGSS) Backend() {}
+
+func (a *AuthenticationGSS) AuthenticationResponse() {}
+
+func (a *AuthenticationGSS) Decode(src []byte) error {
+	if len(src) < 4 {
+		return errors.New("authentication message too short")
+	}
+
+	authType := binary.BigEndian.Uint32(src)
+
+	if authType != AuthTypeGSS {
+		return errors.New("bad auth type")
+	}
+	return nil
+}
+
+func (a *AuthenticationGSS) Encode(dst []byte) []byte {
+	dst = append(dst, 'R')
+	dst = pgio.AppendInt32(dst, 4)
+	dst = pgio.AppendUint32(dst, AuthTypeGSS)
+	return dst
+}
+
+func (a *AuthenticationGSS) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+		Data []byte
+	}{
+		Type: "AuthenticationGSS",
+	})
+}
+
+func (a *AuthenticationGSS) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		Type string
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+	return nil
+}
diff --git a/authentication_gss_continue.go b/authentication_gss_continue.go
new file mode 100644
index 0000000..cf8b183
--- /dev/null
+++ b/authentication_gss_continue.go
@@ -0,0 +1,67 @@
+package pgproto3
+
+import (
+	"encoding/binary"
+	"encoding/json"
+	"errors"
+	"github.com/jackc/pgio"
+)
+
+type AuthenticationGSSContinue struct {
+	Data []byte
+}
+
+func (a *AuthenticationGSSContinue) Backend() {}
+
+func (a *AuthenticationGSSContinue) AuthenticationResponse() {}
+
+func (a *AuthenticationGSSContinue) Decode(src []byte) error {
+	if len(src) < 4 {
+		return errors.New("authentication message too short")
+	}
+
+	authType := binary.BigEndian.Uint32(src)
+
+	if authType != AuthTypeGSSCont {
+		return errors.New("bad auth type")
+	}
+
+	a.Data = src[4:]
+	return nil
+}
+
+func (a *AuthenticationGSSContinue) Encode(dst []byte) []byte {
+	dst = append(dst, 'R')
+	dst = pgio.AppendInt32(dst, int32(len(a.Data))+8)
+	dst = pgio.AppendUint32(dst, AuthTypeGSSCont)
+	dst = append(dst, a.Data...)
+	return dst
+}
+
+func (a *AuthenticationGSSContinue) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+		Data []byte
+	}{
+		Type: "AuthenticationGSSContinue",
+		Data: a.Data,
+	})
+}
+
+func (a *AuthenticationGSSContinue) UnmarshalJSON(data []byte) error {
+	// Ignore null, like in the main JSON package.
+	if string(data) == "null" {
+		return nil
+	}
+
+	var msg struct {
+		Type string
+		Data []byte
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+
+	a.Data = msg.Data
+	return nil
+}
diff --git a/backend.go b/backend.go
index 9c42ad0..1f14365 100644
--- a/backend.go
+++ b/backend.go
@@ -2,6 +2,7 @@ package pgproto3
 
 import (
 	"encoding/binary"
+	"errors"
 	"fmt"
 	"io"
 )
@@ -30,11 +31,10 @@ type Backend struct {
 	sync           Sync
 	terminate      Terminate
 
-	bodyLen      int
-	msgType      byte
-	partialMsg   bool
-	authType     uint32
-	
+	bodyLen    int
+	msgType    byte
+	partialMsg bool
+	authType   uint32
 }
 
 const (
@@ -115,6 +115,9 @@ func (b *Backend) Receive() (FrontendMessage, error) {
 		b.msgType = header[0]
 		b.bodyLen = int(binary.BigEndian.Uint32(header[1:])) - 4
 		b.partialMsg = true
+		if b.bodyLen < 0 {
+			return nil, errors.New("invalid message with negative body length received")
+		}
 	}
 
 	var msg FrontendMessage
@@ -147,6 +150,8 @@ func (b *Backend) Receive() (FrontendMessage, error) {
 			msg = &SASLResponse{}
 		case AuthTypeSASLFinal:
 			msg = &SASLResponse{}
+		case AuthTypeGSS, AuthTypeGSSCont:
+			msg = &GSSResponse{}
 		case AuthTypeCleartextPassword, AuthTypeMD5Password:
 			fallthrough
 		default:
diff --git a/copy_both_response.go b/copy_both_response.go
index fbd985d..4a1c3a0 100644
--- a/copy_both_response.go
+++ b/copy_both_response.go
@@ -48,7 +48,7 @@ func (src *CopyBothResponse) Encode(dst []byte) []byte {
 	dst = append(dst, 'W')
 	sp := len(dst)
 	dst = pgio.AppendInt32(dst, -1)
-
+	dst = append(dst, src.OverallFormat)
 	dst = pgio.AppendUint16(dst, uint16(len(src.ColumnFormatCodes)))
 	for _, fc := range src.ColumnFormatCodes {
 		dst = pgio.AppendUint16(dst, fc)
diff --git a/copy_both_response_test.go b/copy_both_response_test.go
new file mode 100644
index 0000000..d9816fc
--- /dev/null
+++ b/copy_both_response_test.go
@@ -0,0 +1,18 @@
+package pgproto3_test
+
+import (
+	"testing"
+
+	"github.com/jackc/pgproto3/v2"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestEncodeDecode(t *testing.T) {
+	srcBytes := []byte{'W', 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01}
+	dstResp := pgproto3.CopyBothResponse{}
+	err := dstResp.Decode(srcBytes[5:])
+	assert.NoError(t, err, "No errors on decode")
+	dstBytes := []byte{}
+	dstBytes = dstResp.Encode(dstBytes)
+	assert.EqualValues(t, srcBytes, dstBytes, "Expecting src & dest bytes to match")
+}
diff --git a/debian/changelog b/debian/changelog
index 143aa86..87dc3db 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,10 @@
+golang-github-jackc-pgproto3 (2.3.2-1) UNRELEASED; urgency=low
+
+  * New upstream release.
+  * New upstream release.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Mon, 13 Mar 2023 19:39:44 -0000
+
 golang-github-jackc-pgproto3 (2.2.0-2) unstable; urgency=medium
 
   * Source-only upload to unstable
diff --git a/frontend.go b/frontend.go
index c33dfb0..5be8de8 100644
--- a/frontend.go
+++ b/frontend.go
@@ -16,6 +16,8 @@ type Frontend struct {
 	authenticationOk                AuthenticationOk
 	authenticationCleartextPassword AuthenticationCleartextPassword
 	authenticationMD5Password       AuthenticationMD5Password
+	authenticationGSS               AuthenticationGSS
+	authenticationGSSContinue       AuthenticationGSSContinue
 	authenticationSASL              AuthenticationSASL
 	authenticationSASLContinue      AuthenticationSASLContinue
 	authenticationSASLFinal         AuthenticationSASLFinal
@@ -77,6 +79,9 @@ func (f *Frontend) Receive() (BackendMessage, error) {
 		f.msgType = header[0]
 		f.bodyLen = int(binary.BigEndian.Uint32(header[1:])) - 4
 		f.partialMsg = true
+		if f.bodyLen < 0 {
+			return nil, errors.New("invalid message with negative body length received")
+		}
 	}
 
 	msgBody, err := f.cr.Next(f.bodyLen)
@@ -178,9 +183,9 @@ func (f *Frontend) findAuthenticationMessageType(src []byte) (BackendMessage, er
 	case AuthTypeSCMCreds:
 		return nil, errors.New("AuthTypeSCMCreds is unimplemented")
 	case AuthTypeGSS:
-		return nil, errors.New("AuthTypeGSS is unimplemented")
+		return &f.authenticationGSS, nil
 	case AuthTypeGSSCont:
-		return nil, errors.New("AuthTypeGSSCont is unimplemented")
+		return &f.authenticationGSSContinue, nil
 	case AuthTypeSSPI:
 		return nil, errors.New("AuthTypeSSPI is unimplemented")
 	case AuthTypeSASL:
diff --git a/go.sum b/go.sum
index dd9cd04..af83508 100644
--- a/go.sum
+++ b/go.sum
@@ -9,6 +9,7 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/gss_response.go b/gss_response.go
new file mode 100644
index 0000000..62da99c
--- /dev/null
+++ b/gss_response.go
@@ -0,0 +1,48 @@
+package pgproto3
+
+import (
+	"encoding/json"
+	"github.com/jackc/pgio"
+)
+
+type GSSResponse struct {
+	Data []byte
+}
+
+// Frontend identifies this message as sendable by a PostgreSQL frontend.
+func (g *GSSResponse) Frontend() {}
+
+func (g *GSSResponse) Decode(data []byte) error {
+	g.Data = data
+	return nil
+}
+
+func (g *GSSResponse) Encode(dst []byte) []byte {
+	dst = append(dst, 'p')
+	dst = pgio.AppendInt32(dst, int32(4+len(g.Data)))
+	dst = append(dst, g.Data...)
+	return dst
+}
+
+// MarshalJSON implements encoding/json.Marshaler.
+func (g *GSSResponse) MarshalJSON() ([]byte, error) {
+	return json.Marshal(struct {
+		Type string
+		Data []byte
+	}{
+		Type: "GSSResponse",
+		Data: g.Data,
+	})
+}
+
+// UnmarshalJSON implements encoding/json.Unmarshaler.
+func (g *GSSResponse) UnmarshalJSON(data []byte) error {
+	var msg struct {
+		Data []byte
+	}
+	if err := json.Unmarshal(data, &msg); err != nil {
+		return err
+	}
+	g.Data = msg.Data
+	return nil
+}
diff --git a/json_test.go b/json_test.go
index eab2625..9556c27 100644
--- a/json_test.go
+++ b/json_test.go
@@ -37,6 +37,32 @@ func TestJSONUnmarshalAuthenticationSASL(t *testing.T) {
 	}
 }
 
+func TestJSONUnmarshalAuthenticationGSS(t *testing.T) {
+	data := []byte(`{"Type":"AuthenticationGSS"}`)
+	want := AuthenticationGSS{}
+
+	var got AuthenticationGSS
+	if err := json.Unmarshal(data, &got); err != nil {
+		t.Errorf("cannot JSON unmarshal %v", err)
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Error("unmarshaled AuthenticationGSS struct doesn't match expected value")
+	}
+}
+
+func TestJSONUnmarshalAuthenticationGSSContinue(t *testing.T) {
+	data := []byte(`{"Type":"AuthenticationGSSContinue","Data":[1,2,3,4]}`)
+	want := AuthenticationGSSContinue{Data: []byte{1, 2, 3, 4}}
+
+	var got AuthenticationGSSContinue
+	if err := json.Unmarshal(data, &got); err != nil {
+		t.Errorf("cannot JSON unmarshal %v", err)
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Error("unmarshaled AuthenticationGSSContinue struct doesn't match expected value")
+	}
+}
+
 func TestJSONUnmarshalAuthenticationSASLContinue(t *testing.T) {
 	data := []byte(`{"Type":"AuthenticationSASLContinue", "Data":"1"}`)
 	want := AuthenticationSASLContinue{
@@ -463,10 +489,10 @@ func TestJSONUnmarshalQuery(t *testing.T) {
 }
 
 func TestJSONUnmarshalSASLInitialResponse(t *testing.T) {
-	data := []byte(`{"Type":"SASLInitialResponse", "AuthMechanism":"SCRAM-SHA-256", "Data": "6D"}`)
+	data := []byte(`{"Type":"SASLInitialResponse", "AuthMechanism":"SCRAM-SHA-256", "Data": "abc"}`)
 	want := SASLInitialResponse{
 		AuthMechanism: "SCRAM-SHA-256",
-		Data:          []byte{109},
+		Data:          []byte("abc"),
 	}
 
 	var got SASLInitialResponse
@@ -479,8 +505,10 @@ func TestJSONUnmarshalSASLInitialResponse(t *testing.T) {
 }
 
 func TestJSONUnmarshalSASLResponse(t *testing.T) {
-	data := []byte(`{"Type":"SASLResponse","Message":"abc"}`)
-	want := SASLResponse{}
+	data := []byte(`{"Type":"SASLResponse","Data":"abc"}`)
+	want := SASLResponse{
+		Data: []byte("abc"),
+	}
 
 	var got SASLResponse
 	if err := json.Unmarshal(data, &got); err != nil {
@@ -551,6 +579,19 @@ func TestAuthenticationMD5Password(t *testing.T) {
 	}
 }
 
+func TestJSONUnmarshalGSSResponse(t *testing.T) {
+	data := []byte(`{"Type":"GSSResponse","Data":[10,20,30,40]}`)
+	want := GSSResponse{Data: []byte{10, 20, 30, 40}}
+
+	var got GSSResponse
+	if err := json.Unmarshal(data, &got); err != nil {
+		t.Errorf("cannot JSON unmarshal %v", err)
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Error("unmarshaled GSSResponse struct doesn't match expected value")
+	}
+}
+
 func TestErrorResponse(t *testing.T) {
 	data := []byte(`{"Type":"ErrorResponse","UnknownFields":{"112":"foo"},"Code": "Fail","Position":1,"Message":"this is an error"}`)
 	want := ErrorResponse{
diff --git a/sasl_initial_response.go b/sasl_initial_response.go
index f862f2a..a6b553e 100644
--- a/sasl_initial_response.go
+++ b/sasl_initial_response.go
@@ -2,7 +2,6 @@ package pgproto3
 
 import (
 	"bytes"
-	"encoding/hex"
 	"encoding/json"
 	"errors"
 
@@ -83,12 +82,6 @@ func (dst *SASLInitialResponse) UnmarshalJSON(data []byte) error {
 		return err
 	}
 	dst.AuthMechanism = msg.AuthMechanism
-	if msg.Data != "" {
-		decoded, err := hex.DecodeString(msg.Data)
-		if err != nil {
-			return err
-		}
-		dst.Data = decoded
-	}
+	dst.Data = []byte(msg.Data)
 	return nil
 }
diff --git a/sasl_response.go b/sasl_response.go
index d402759..d3e5d6a 100644
--- a/sasl_response.go
+++ b/sasl_response.go
@@ -1,7 +1,6 @@
 package pgproto3
 
 import (
-	"encoding/hex"
 	"encoding/json"
 
 	"github.com/jackc/pgio"
@@ -50,12 +49,6 @@ func (dst *SASLResponse) UnmarshalJSON(data []byte) error {
 	if err := json.Unmarshal(data, &msg); err != nil {
 		return err
 	}
-	if msg.Data != "" {
-		decoded, err := hex.DecodeString(msg.Data)
-		if err != nil {
-			return err
-		}
-		dst.Data = decoded
-	}
+	dst.Data = []byte(msg.Data)
 	return nil
 }

Debdiff

[The following lists of changes regard files as different if they have different names, permissions or owners.]

Files in second set of .debs but not in first

-rw-r--r--  root/root   /usr/share/gocode/src/github.com/jackc/pgproto3/v2/authentication_gss.go
-rw-r--r--  root/root   /usr/share/gocode/src/github.com/jackc/pgproto3/v2/authentication_gss_continue.go
-rw-r--r--  root/root   /usr/share/gocode/src/github.com/jackc/pgproto3/v2/copy_both_response_test.go
-rw-r--r--  root/root   /usr/share/gocode/src/github.com/jackc/pgproto3/v2/gss_response.go

No differences were encountered in the control files

More details

Full run details