From 4eb3bdaa13d77ab7f828503689a020efd41438e6 Mon Sep 17 00:00:00 2001 From: Alexandre Tuleu Date: Mon, 17 Aug 2015 13:50:16 +0200 Subject: [PATCH] Adds an internal library for JWS / JWT encoding --- jwt/.gitignore | 1 + jwt/Makefile | 9 +++++++ jwt/base64.go | 32 +++++++++++++++++++++++ jwt/base64_test.go | 63 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 105 insertions(+) create mode 100644 jwt/.gitignore create mode 100644 jwt/Makefile create mode 100644 jwt/base64.go create mode 100644 jwt/base64_test.go diff --git a/jwt/.gitignore b/jwt/.gitignore new file mode 100644 index 0000000..b51c70b --- /dev/null +++ b/jwt/.gitignore @@ -0,0 +1 @@ +cover.out diff --git a/jwt/Makefile b/jwt/Makefile new file mode 100644 index 0000000..478df7c --- /dev/null +++ b/jwt/Makefile @@ -0,0 +1,9 @@ +all: build check + +build: + go build + +check: + go test -coverprofile=cover.out -covermode=count + go vet + golint diff --git a/jwt/base64.go b/jwt/base64.go new file mode 100644 index 0000000..43c7e6e --- /dev/null +++ b/jwt/base64.go @@ -0,0 +1,32 @@ +package jwt + +import ( + "encoding/base64" + "fmt" + "strings" +) + +// Base64Encode encodes a payload of data as a string, like specified +// in RFC 7515 (no trailing '=' +func Base64Encode(b []byte) string { + return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=") +} + +// Base64Decode decodes a payload of data as a []byte, like specified +// in RFC 7515 (no trailing '=') +func Base64Decode(s string) ([]byte, error) { + switch len(s) % 4 { + case 2: + s += "==" + case 3: + s += "=" + case 1: + return nil, fmt.Errorf("jwt: Invalid base64 string (length:%d %% 4 == 1): '%s'", len(s), s) + } + d, err := base64.URLEncoding.DecodeString(s) + if err != nil { + return nil, fmt.Errorf("jwt: %s", err) + } + return d, nil + +} diff --git a/jwt/base64_test.go b/jwt/base64_test.go new file mode 100644 index 0000000..5bb17d1 --- /dev/null +++ b/jwt/base64_test.go @@ -0,0 +1,63 @@ +package jwt + +import ( + "testing" + + . "gopkg.in/check.v1" +) + +func Test(t *testing.T) { + TestingT(t) +} + +type Base64Suite struct{} + +var _ = Suite(&Base64Suite{}) + +type dataAndEncode struct { + data []byte + encoded string +} + +func (s *Base64Suite) TestEncodeWithNoTrailing(c *C) { + data := []dataAndEncode{ + {[]byte{0, 0, 0}, "AAAA"}, //With trailing Should be AAAA + {[]byte{0, 0}, "AAA"}, //With trailing Should be AAA= + {[]byte{0}, "AA"}, //With trailing Should be AA== + } + + for _, d := range data { + res := Base64Encode(d.data) + c.Check(res, Equals, d.encoded) + } + +} + +func (s *Base64Suite) TestDecodeWithNoTrailing(c *C) { + data := map[string][]byte{ + "AAAA": []byte{0, 0, 0}, + "AAA": []byte{0, 0}, + "AA": []byte{0}, + } + + for encoded, expected := range data { + res, err := Base64Decode(encoded) + if c.Check(err, IsNil) == false { + continue + } + c.Check(res, DeepEquals, expected) + } +} + +func (s *Base64Suite) TestDetectBadFormat(c *C) { + data := map[string]string{ + "A": `jwt: Invalid base64 string \(length:[0-9]+ % 4 == 1\): 'A'`, + "ABCD%===": `jwt: illegal base64 data at input byte [0-9]+`, + } + + for encoded, errorMatches := range data { + res, err := Base64Decode(encoded) + c.Check(err, ErrorMatches, errorMatches) + c.Check(res, IsNil) + } +}