Skip to content

Commit 0a59ee4

Browse files
authored
Merge pull request #12 from aidantwoods/sentinel-errors
Add sentinel error types
2 parents 9baac02 + 315beca commit 0a59ee4

File tree

7 files changed

+105
-16
lines changed

7 files changed

+105
-16
lines changed

claims_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ func TestFutureIat(t *testing.T) {
127127

128128
_, err := parser.ParseV4Local(key, encrypted, nil)
129129
require.Error(t, err)
130+
require.ErrorIs(t, err, &paseto.RuleError{})
131+
require.NotErrorIs(t, err, &paseto.TokenError{})
130132
}
131133

132134
func TestFutureNbf(t *testing.T) {
@@ -146,6 +148,8 @@ func TestFutureNbf(t *testing.T) {
146148

147149
_, err := parser.ParseV4Local(key, encrypted, nil)
148150
require.Error(t, err)
151+
require.ErrorIs(t, err, &paseto.RuleError{})
152+
require.NotErrorIs(t, err, &paseto.TokenError{})
149153
}
150154

151155
func TestFutureNbfNotBeforeNbfRule(t *testing.T) {
@@ -184,6 +188,8 @@ func TestFutureNbfNotBeforeNbfRuleError(t *testing.T) {
184188

185189
_, err := parser.ParseV4Local(key, encrypted, nil)
186190
require.Error(t, err)
191+
require.ErrorIs(t, err, &paseto.RuleError{})
192+
require.NotErrorIs(t, err, &paseto.TokenError{})
187193
}
188194

189195
func TestPastExp(t *testing.T) {
@@ -203,6 +209,8 @@ func TestPastExp(t *testing.T) {
203209

204210
_, err := parser.ParseV4Local(key, encrypted, nil)
205211
require.Error(t, err)
212+
require.ErrorIs(t, err, &paseto.RuleError{})
213+
require.NotErrorIs(t, err, &paseto.TokenError{})
206214
}
207215

208216
func TestReadMeExample(t *testing.T) {

errors.go

Lines changed: 58 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,51 @@ package paseto
22

33
import "fmt"
44

5+
// Any cryptography issue (with the token) or formatting error.
6+
// This does not include cryptography errors with input key material, these will
7+
// return regular errors.
8+
type TokenError struct {
9+
e error
10+
}
11+
12+
func (e *TokenError) Error() string {
13+
return e.e.Error()
14+
}
15+
16+
func (_ *TokenError) Is(e error) bool {
17+
_, ok := e.(*TokenError)
18+
return ok
19+
}
20+
21+
func (e *TokenError) Unwrap() error {
22+
return e.e
23+
}
24+
25+
func (e *TokenError) wrapWith(msg string) *TokenError {
26+
return &TokenError{fmt.Errorf("%s: %w", msg, e)}
27+
}
28+
29+
// Any error which is the result of a rule failure (distinct from a TokenError)
30+
// Can be used to detect cryptographically valid tokens which have failed only
31+
// due to a rule failure: which may warrant a slightly different processing
32+
// follow up.
33+
type RuleError struct {
34+
e error
35+
}
36+
37+
func (e *RuleError) Error() string {
38+
return e.e.Error()
39+
}
40+
41+
func (_ *RuleError) Is(e error) bool {
42+
_, ok := e.(*RuleError)
43+
return ok
44+
}
45+
46+
func (e *RuleError) Unwrap() error {
47+
return e.e
48+
}
49+
550
func errorKeyLength(expected, given int) error {
651
return fmt.Errorf("key length incorrect (%d), expected %d", given, expected)
752
}
@@ -10,32 +55,32 @@ func errorSeedLength(expected, given int) error {
1055
return fmt.Errorf("seed length incorrect (%d), expected %d", given, expected)
1156
}
1257

13-
func errorMessageParts(given int) error {
14-
return fmt.Errorf("invalid number of message parts in token (%d)", given)
58+
func errorMessageParts(given int) *TokenError {
59+
return &TokenError{fmt.Errorf("invalid number of message parts in token (%d)", given)}
1560
}
1661

17-
func errorMessageHeader(expected Protocol, givenHeader string) error {
18-
return fmt.Errorf("message header `%s' is not valid, expected `%s'", givenHeader, expected.Header())
62+
func errorMessageHeader(expected Protocol, givenHeader string) *TokenError {
63+
return &TokenError{fmt.Errorf("message header `%s' is not valid, expected `%s'", givenHeader, expected.Header())}
1964
}
2065

21-
func errorMessageHeaderDecrypt(expected Protocol, givenHeader string) error {
22-
return fmt.Errorf("cannot decrypt message: %w", errorMessageHeader(expected, givenHeader))
66+
func errorMessageHeaderDecrypt(expected Protocol, givenHeader string) *TokenError {
67+
return errorMessageHeader(expected, givenHeader).wrapWith("cannot decrypt message")
2368
}
2469

25-
func errorMessageHeaderVerify(expected Protocol, givenHeader string) error {
26-
return fmt.Errorf("cannot verify message: %w", errorMessageHeader(expected, givenHeader))
70+
func errorMessageHeaderVerify(expected Protocol, givenHeader string) *TokenError {
71+
return errorMessageHeader(expected, givenHeader).wrapWith("cannot verify message")
2772
}
2873

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

33-
var errorPayloadShort = fmt.Errorf("payload is not long enough to be a valid PASETO message")
34-
var errorBadSignature = fmt.Errorf("bad signature")
35-
var errorBadMAC = fmt.Errorf("bad message authentication code")
78+
var errorPayloadShort = &TokenError{fmt.Errorf("payload is not long enough to be a valid PASETO message")}
79+
var errorBadSignature = &TokenError{fmt.Errorf("bad signature")}
80+
var errorBadMAC = &TokenError{fmt.Errorf("bad message authentication code")}
3681

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

39-
func errorDecrypt(err error) error {
40-
return fmt.Errorf("the message could not be decrypted: %w", err)
84+
func errorDecrypt(err error) *TokenError {
85+
return (&TokenError{err}).wrapWith("the message could not be decrypted")
4186
}

keys_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ func TestV2AsymmetricSecretKeyImport(t *testing.T) {
1212

1313
_, err := paseto.NewV2AsymmetricSecretKeyFromHex(badKey)
1414
require.Error(t, err)
15+
require.NotErrorIs(t, err, &paseto.RuleError{})
16+
require.NotErrorIs(t, err, &paseto.TokenError{})
1517

1618
goodKey := "b4cbfb43df4ce210727d953e4a713307fa19bb7d9f85041438d9e11b942a37741eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2"
1719

@@ -24,6 +26,8 @@ func TestV4AsymmetricSecretKeyImport(t *testing.T) {
2426

2527
_, err := paseto.NewV4AsymmetricSecretKeyFromHex(badKey)
2628
require.Error(t, err)
29+
require.NotErrorIs(t, err, &paseto.RuleError{})
30+
require.NotErrorIs(t, err, &paseto.TokenError{})
2731

2832
goodKey := "b4cbfb43df4ce210727d953e4a713307fa19bb7d9f85041438d9e11b942a37741eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2"
2933

message.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,12 @@ func newMessage(protocol Protocol, token string) (message, error) {
2929

3030
payloadBytes, err := encoding.Decode(encodedPayload)
3131
if err != nil {
32-
return message{}, err
32+
return message{}, &TokenError{err}
3333
}
3434

3535
footer, err := encoding.Decode(encodedFooter)
3636
if err != nil {
37-
return message{}, err
37+
return message{}, &TokenError{err}
3838
}
3939

4040
payload, err := protocol.newPayload(payloadBytes)

parser.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ func (p *Parser) AddRule(rule ...Rule) {
152152
func (p Parser) validate(token Token) (*Token, error) {
153153
for _, rule := range p.rules {
154154
if err := rule(token); err != nil {
155-
return nil, err
155+
return nil, &RuleError{err}
156156
}
157157
}
158158

token_test.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ func TestSomeInt(t *testing.T) {
2929
var output string
3030
err = token.Get("foo", &output)
3131
require.Error(t, err)
32+
require.NotErrorIs(t, err, &paseto.RuleError{})
33+
require.NotErrorIs(t, err, &paseto.TokenError{})
3234

3335
var intOutput int
3436
err = token.Get("foo", &intOutput)
@@ -46,6 +48,8 @@ func TestSomeBool(t *testing.T) {
4648
var intOutput int
4749
err = token.Get("foo", &intOutput)
4850
require.Error(t, err)
51+
require.NotErrorIs(t, err, &paseto.RuleError{})
52+
require.NotErrorIs(t, err, &paseto.TokenError{})
4953

5054
var output bool
5155
err = token.Get("foo", &output)
@@ -92,6 +96,8 @@ func TestSomeWrongType(t *testing.T) {
9296
var output bool
9397
err = token.Get("baz", &output)
9498
require.Error(t, err)
99+
require.NotErrorIs(t, err, &paseto.RuleError{})
100+
require.NotErrorIs(t, err, &paseto.TokenError{})
95101
}
96102

97103
func TestSomeWrongKey(t *testing.T) {
@@ -103,6 +109,8 @@ func TestSomeWrongKey(t *testing.T) {
103109
var output string
104110
err = token.Get("bar", &output)
105111
require.Error(t, err)
112+
require.NotErrorIs(t, err, &paseto.RuleError{})
113+
require.NotErrorIs(t, err, &paseto.TokenError{})
106114
}
107115

108116
func TestFromMap(t *testing.T) {

vectors_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,17 @@ func TestV2(t *testing.T) {
5050
message, err := paseto.NewMessage(paseto.V2Local, test.Token)
5151
if test.ExpectFail {
5252
require.Error(t, err)
53+
require.ErrorIs(t, err, &paseto.TokenError{})
54+
require.NotErrorIs(t, err, &paseto.RuleError{})
5355
return
5456
}
5557
require.NoError(t, err)
5658

5759
decoded, err = paseto.V2LocalDecrypt(message, sk)
5860
if test.ExpectFail {
5961
require.Error(t, err)
62+
require.ErrorIs(t, err, &paseto.TokenError{})
63+
require.NotErrorIs(t, err, &paseto.RuleError{})
6064
return
6165
}
6266
require.NoError(t, err)
@@ -69,13 +73,17 @@ func TestV2(t *testing.T) {
6973
message, err := paseto.NewMessage(paseto.V2Public, test.Token)
7074
if test.ExpectFail {
7175
require.Error(t, err)
76+
require.ErrorIs(t, err, &paseto.TokenError{})
77+
require.NotErrorIs(t, err, &paseto.RuleError{})
7278
return
7379
}
7480
require.NoError(t, err)
7581

7682
decoded, err = paseto.V2PublicVerify(message, pk)
7783
if test.ExpectFail {
7884
require.Error(t, err)
85+
require.ErrorIs(t, err, &paseto.TokenError{})
86+
require.NotErrorIs(t, err, &paseto.RuleError{})
7987
return
8088
}
8189
require.NoError(t, err)
@@ -135,13 +143,17 @@ func TestV3(t *testing.T) {
135143
message, err := paseto.NewMessage(paseto.V3Local, test.Token)
136144
if test.ExpectFail {
137145
require.Error(t, err)
146+
require.ErrorIs(t, err, &paseto.TokenError{})
147+
require.NotErrorIs(t, err, &paseto.RuleError{})
138148
return
139149
}
140150
require.NoError(t, err)
141151

142152
decoded, err = paseto.V3LocalDecrypt(message, sk, []byte(test.ImplicitAssertation))
143153
if test.ExpectFail {
144154
require.Error(t, err)
155+
require.ErrorIs(t, err, &paseto.TokenError{})
156+
require.NotErrorIs(t, err, &paseto.RuleError{})
145157
return
146158
}
147159
require.NoError(t, err)
@@ -154,13 +166,17 @@ func TestV3(t *testing.T) {
154166
message, err := paseto.NewMessage(paseto.V3Public, test.Token)
155167
if test.ExpectFail {
156168
require.Error(t, err)
169+
require.ErrorIs(t, err, &paseto.TokenError{})
170+
require.NotErrorIs(t, err, &paseto.RuleError{})
157171
return
158172
}
159173
require.NoError(t, err)
160174

161175
decoded, err = paseto.V3PublicVerify(message, pk, []byte(test.ImplicitAssertation))
162176
if test.ExpectFail {
163177
require.Error(t, err)
178+
require.ErrorIs(t, err, &paseto.TokenError{})
179+
require.NotErrorIs(t, err, &paseto.RuleError{})
164180
return
165181
}
166182
require.NoError(t, err)
@@ -235,13 +251,17 @@ func TestV4(t *testing.T) {
235251
message, err := paseto.NewMessage(paseto.V4Local, test.Token)
236252
if test.ExpectFail {
237253
require.Error(t, err)
254+
require.ErrorIs(t, err, &paseto.TokenError{})
255+
require.NotErrorIs(t, err, &paseto.RuleError{})
238256
return
239257
}
240258
require.NoError(t, err)
241259

242260
decoded, err = paseto.V4LocalDecrypt(message, sk, []byte(test.ImplicitAssertation))
243261
if test.ExpectFail {
244262
require.Error(t, err)
263+
require.ErrorIs(t, err, &paseto.TokenError{})
264+
require.NotErrorIs(t, err, &paseto.RuleError{})
245265
return
246266
}
247267
require.NoError(t, err)
@@ -254,13 +274,17 @@ func TestV4(t *testing.T) {
254274
message, err := paseto.NewMessage(paseto.V4Public, test.Token)
255275
if test.ExpectFail {
256276
require.Error(t, err)
277+
require.ErrorIs(t, err, &paseto.TokenError{})
278+
require.NotErrorIs(t, err, &paseto.RuleError{})
257279
return
258280
}
259281
require.NoError(t, err)
260282

261283
decoded, err = paseto.V4PublicVerify(message, pk, []byte(test.ImplicitAssertation))
262284
if test.ExpectFail {
263285
require.Error(t, err)
286+
require.ErrorIs(t, err, &paseto.TokenError{})
287+
require.NotErrorIs(t, err, &paseto.RuleError{})
264288
return
265289
}
266290
require.NoError(t, err)

0 commit comments

Comments
 (0)