Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Result type #19

Merged
merged 12 commits into from
May 6, 2023
56 changes: 33 additions & 23 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,26 @@ type TokenError struct {
e error
}

func (e *TokenError) Error() string {
func newTokenError(e error) TokenError {
return TokenError{e}
}

func (e TokenError) Error() string {
return e.e.Error()
}

func (_ *TokenError) Is(e error) bool {
_, ok := e.(*TokenError)
return ok
func (_ TokenError) Is(e error) bool {
_, ok1 := e.(TokenError)
_, ok2 := e.(*TokenError)
return ok1 || ok2
}

func (e *TokenError) Unwrap() error {
func (e TokenError) Unwrap() error {
return e.e
}

func (e *TokenError) wrapWith(msg string) *TokenError {
return &TokenError{fmt.Errorf("%s: %w", msg, e)}
func (e TokenError) wrapWith(msg string) TokenError {
return TokenError{fmt.Errorf("%s: %w", msg, e)}
}

// Any error which is the result of a rule failure (distinct from a TokenError)
Expand All @@ -34,16 +39,21 @@ type RuleError struct {
e error
}

func (e *RuleError) Error() string {
func newRuleError(e error) RuleError {
return RuleError{e}
}

func (e RuleError) Error() string {
return e.e.Error()
}

func (_ *RuleError) Is(e error) bool {
_, ok := e.(*RuleError)
return ok
func (_ RuleError) Is(e error) bool {
_, ok1 := e.(RuleError)
_, ok2 := e.(*RuleError)
return ok1 || ok2
}

func (e *RuleError) Unwrap() error {
func (e RuleError) Unwrap() error {
return e.e
}

Expand All @@ -55,32 +65,32 @@ func errorSeedLength(expected, given int) error {
return fmt.Errorf("seed length incorrect (%d), expected %d", given, expected)
}

func errorMessageParts(given int) *TokenError {
return &TokenError{fmt.Errorf("invalid number of message parts in token (%d)", given)}
func errorMessageParts(given int) TokenError {
return newTokenError(fmt.Errorf("invalid number of message parts in token (%d)", given))
}

func errorMessageHeader(expected Protocol, givenHeader string) *TokenError {
return &TokenError{fmt.Errorf("message header `%s' is not valid, expected `%s'", givenHeader, expected.Header())}
func errorMessageHeader(expected Protocol, givenHeader string) TokenError {
return newTokenError(fmt.Errorf("message header `%s' is not valid, expected `%s'", givenHeader, expected.Header()))
}

func errorMessageHeaderDecrypt(expected Protocol, givenHeader string) *TokenError {
func errorMessageHeaderDecrypt(expected Protocol, givenHeader string) TokenError {
return errorMessageHeader(expected, givenHeader).wrapWith("cannot decrypt message")
}

func errorMessageHeaderVerify(expected Protocol, givenHeader string) *TokenError {
func errorMessageHeaderVerify(expected Protocol, givenHeader string) TokenError {
return errorMessageHeader(expected, givenHeader).wrapWith("cannot verify message")
}

var unsupportedPasetoVersion = fmt.Errorf("unsupported PASETO version")
var unsupportedPasetoPurpose = fmt.Errorf("unsupported PASETO purpose")
var unsupportedPayload = fmt.Errorf("unsupported payload")

var errorPayloadShort = &TokenError{fmt.Errorf("payload is not long enough to be a valid PASETO message")}
var errorBadSignature = &TokenError{fmt.Errorf("bad signature")}
var errorBadMAC = &TokenError{fmt.Errorf("bad message authentication code")}
var errorPayloadShort = newTokenError(fmt.Errorf("payload is not long enough to be a valid PASETO message"))
var errorBadSignature = newTokenError(fmt.Errorf("bad signature"))
var errorBadMAC = newTokenError(fmt.Errorf("bad message authentication code"))

var errorKeyInvalid = fmt.Errorf("key was not valid")

func errorDecrypt(err error) *TokenError {
return (&TokenError{err}).wrapWith("the message could not be decrypted")
func errorDecrypt(err error) TokenError {
return newTokenError(err).wrapWith("the message could not be decrypted")
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module aidanwoods.dev/go-paseto
go 1.18

require (
aidanwoods.dev/go-result v0.0.0-20230310133209-26c34aabd0c7
github.com/stretchr/testify v1.7.0
golang.org/x/crypto v0.7.0
)
Expand Down
35 changes: 2 additions & 33 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
aidanwoods.dev/go-result v0.0.0-20230310133209-26c34aabd0c7 h1:bVUDSxup1h+a2DenqxeTWRschTdSMmo1Cy5/LxnzCtc=
aidanwoods.dev/go-result v0.0.0-20230310133209-26c34aabd0c7/go.mod h1:yridkWghM7AXSFA6wzx0IbsurIm1Lhuro3rYef8FBHM=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -6,43 +8,10 @@ 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.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
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.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Expand Down
8 changes: 5 additions & 3 deletions internal/encoding/base64.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"encoding/base64"
"errors"
"strings"

t "aidanwoods.dev/go-result"
)

var b64 = base64.RawURLEncoding.Strict()
Expand All @@ -14,12 +16,12 @@ func Encode(bytes []byte) string {
}

// Decode Standard decoding for Paseto is URL safe base64 with no padding
func Decode(encoded string) ([]byte, error) {
func Decode(encoded string) t.Result[[]byte] {
// From: https://pkg.go.dev/encoding/base64#Encoding.Strict
// Note that the input is still malleable, as new line characters (CR and LF) are still ignored.
if strings.ContainsAny(encoded, "\n\r") {
return nil, errors.New("Input may not contain new lines")
return t.Err[[]byte](errors.New("Input may not contain new lines"))
}

return b64.DecodeString(encoded)
return t.NewResult(b64.DecodeString(encoded))
}
17 changes: 17 additions & 0 deletions internal/encoding/hex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package encoding

import (
"encoding/hex"

t "aidanwoods.dev/go-result"
)

// Encode hex
func HexEncode(bytes []byte) string {
return hex.EncodeToString(bytes)
}

// Decode hex
func HexDecode(encoded string) t.Result[[]byte] {
return t.NewResult(hex.DecodeString(encoded))
}
18 changes: 9 additions & 9 deletions internal/encoding/paseto.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,25 @@ package encoding
import (
"bytes"
"encoding/binary"

t "aidanwoods.dev/go-result"
)

// Pae Pre Auth Encode
func Pae(pieces ...[]byte) []byte {
buffer := &bytes.Buffer{}

// MSB should be zero
if err := binary.Write(buffer, binary.LittleEndian, int64(len(pieces))); err != nil {
panic("Cannot write to buffer")
}
t.NewVoidResult(binary.Write(buffer, binary.LittleEndian, int64(len(pieces)))).
Expect("writing to buffer should not fail")

for i := range pieces {
// MSB should be zero
if err := binary.Write(buffer, binary.LittleEndian, int64(len(pieces[i]))); err != nil {
panic("Cannot write to buffer")
}
if _, err := buffer.Write(pieces[i]); err != nil {
panic("Cannot write to buffer")
}
t.NewVoidResult(binary.Write(buffer, binary.LittleEndian, int64(len(pieces[i])))).
Expect("writing to buffer should not fail")

t.NewResult(buffer.Write(pieces[i])).
Expect("writing to buffer should not fail")
}

return buffer.Bytes()
Expand Down
16 changes: 5 additions & 11 deletions internal/hashing/hashing.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
package hashing

import (
"hash"

t "aidanwoods.dev/go-result"
"golang.org/x/crypto/blake2b"
)

// GenericHash The same as crypto_generichash as referred to in the Paseto spec
func GenericHash(in, out, key []byte) {
var blake hash.Hash
var err error

if blake, err = blake2b.New(len(out), key); err != nil {
panic(err)
}
blake := t.NewResult(blake2b.New(len(out), key)).
Expect("blake2 hasher construction should be provided with valid length inputs")

if _, err = blake.Write(in); err != nil {
panic(err)
}
t.NewResult(blake.Write(in)).
Expect("writing into hasher should not fail")

copy(out, blake.Sum(nil))
}
8 changes: 3 additions & 5 deletions internal/random/random.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,13 @@ package random
import (
"crypto/rand"
"io"

t "aidanwoods.dev/go-result"
)

// FillBytes fills out with random bytes from the OS CSPRNG, or panics
func FillBytes(out []byte) {
_, err := io.ReadFull(rand.Reader, out[:])

if err != nil {
panic("CSPRNG failure")
}
t.NewResult(io.ReadFull(rand.Reader, out[:])).Expect("CSPRNG failure")
}

// UseProvidedOrFillBytes will fill `out' with unitTestNonce, provided it is
Expand Down
Loading