You are an expert in writing code in many different languages. Your goal is to perform code completion for the following code, keeping in mind the rest of the code and the file meta data.
    Metadata details:
    filename: frontend.go
    path of file: ./repos/acra/decryptor/postgresql/testutils
    
    the code of the file until where you have to start completion: package testutils

import (
	"context"
	"crypto/md5"
	"crypto/tls"
	"encoding/hex"
	"errors"
	"fmt"
	"github.com/cossacklabs/acra/utils/tests"
	"github.com/jackc/pgx/v5/pgproto3"
	"io"
	"net"
	"reflect"
)

// Frontend extends pgproto3.Frontend
type Frontend struct {
	*pgproto3.Frontend
	connIn, connOut net.Conn
}

// NewFrontend returns new Frontend
func NewFrontend(connIn, connOut net.Conn) *Frontend {
	f := pgproto3.NewFrontend(connIn, connOut)
	return &Frontend{Frontend: f, connIn: connIn, connOut: connOut}
}

// Valid responses on SSLRequest
const (
	SSLRequestOk = 'S'
	SSLRequestNo = 'N'
)

// ReadSSLResponse reads and returns response on SSLRequest
func (f *Frontend) ReadSSLResponse() (byte, error) {
	var out [1]byte
	_, err := f.connIn.Read(out[:])
	return out[0], err
}

// Close sends Terminate packet and closes connections
func (f *Frontend) Close() error {
	f.Send(&pgproto3.Terminate{})
	err := f.connOut.Close()
	if f.connOut != f.connIn {
		err2 := f.connIn.Close()
		if err == nil {
			err = err2
		}
	}
	return err
}

// SwitchToTLS switch frontend's connections to the TLS. Expects that databa
    
func (step authStep) Step(frontend *Frontend) error {
	if tests.TestWithTLS() {
		frontend.Send(&pgproto3.SSLRequest{})
		if err := frontend.Flush(); err != nil {
			return err
		}
		response, err := frontend.ReadSSLResponse()
		if err != nil {
			return err
		}
		if response == SSLRequestNo {
			return errors.New("postgresql denied SSLRequest")
		}
		if err = frontend.SwitchToTLS(step.ctx, step.tlsConfig); err != nil {
			return err
		}
	}

	frontend.Send(&pgproto3.StartupMessage{pgproto3.ProtocolVersionNumber, map[string]string{
		"user":     step.username,
		"database": step.database,
	}})
	err := frontend.Flush()
	if err != nil {
		return err
	}
	msg, err := frontend.Receive()
	if err != nil {
		return err
	}
	_, ok := msg.(*pgproto3.AuthenticationOk)
	if ok {
		return WaitForStep(&pgproto3.ReadyForQuery{}).Step(frontend)
	}
	md5Msg, ok := msg.(*pgproto3.AuthenticationMD5Password)
	if !ok {
		return fmt.Errorf("msg => %#v, e.want => %#v", msg, &pgproto3.AuthenticationMD5Password{})
	}
	// took from github.com/jackc/pgx/v5@v5.2.0/pgconn/pgconn.go
	hexMD5 := func(s string) string {
		hash := md5.New()
		io.WriteString(hash, s)
		return hex.EncodeToString(hash.Sum(nil))
	}
	digestedPassword := "md5" + hexMD5(hexMD5(step.password+step.username)+string(md5Msg.Salt[:]))
	frontend.Send(&pgproto3.PasswordMessage{Password: digestedPassword})
	err = frontend.Flush()
	if err != nil {
		return err
	}
	return WaitForStep(&pgproto3.ReadyForQuery{}).Step(frontend)
}