aboutsummaryrefslogtreecommitdiff
path: root/securecookie.go
diff options
context:
space:
mode:
authorMatt Silverlock <matt@eatsleeprepeat.net>2015-05-16 20:50:49 +0300
committerMatt Silverlock <matt@eatsleeprepeat.net>2015-05-16 20:50:49 +0300
commit978e3ebadae78bf30fec1524c0a264e1b8190d2e (patch)
tree4ba7a6267f45db1a27c06b110405541a41178454 /securecookie.go
parent8e98dd730fc43f1383f19615db6f2e702c9738e8 (diff)
Added a JSON encoder/decoder to securecookie.
A new "Encoder" interface with serialize/deserialize methods allows custom encoders to be specified. encoding/gob remains the default for compatibility/ease-of-use reasons, but the (often faster) encoding/json is now an option.
Diffstat (limited to 'securecookie.go')
-rw-r--r--securecookie.go57
1 files changed, 53 insertions, 4 deletions
diff --git a/securecookie.go b/securecookie.go
index 1b7acf8..8ed512a 100644
--- a/securecookie.go
+++ b/securecookie.go
@@ -14,6 +14,7 @@ import (
"crypto/subtle"
"encoding/base64"
"encoding/gob"
+ "encoding/json"
"errors"
"fmt"
"hash"
@@ -44,6 +45,7 @@ type Codec interface {
// GenerateRandomKey(). The key length must correspond to the block size
// of the encryption algorithm. For AES, used by default, valid lengths are
// 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
+// The default encoder used for cookie serialization is encoding/gob.
func New(hashKey, blockKey []byte) *SecureCookie {
s := &SecureCookie{
hashKey: hashKey,
@@ -51,6 +53,7 @@ func New(hashKey, blockKey []byte) *SecureCookie {
hashFunc: sha256.New,
maxAge: 86400 * 30,
maxLength: 4096,
+ enc: GobEncoder{},
}
if hashKey == nil {
s.err = errHashKeyNotSet
@@ -72,11 +75,28 @@ type SecureCookie struct {
maxAge int64
minAge int64
err error
+ enc encoder
// For testing purposes, the function that returns the current timestamp.
// If not set, it will use time.Now().UTC().Unix().
timeFunc func() int64
}
+// Encoder provides an interface for providing custom encoders for cookie
+// values.
+type encoder interface {
+ serialize(src interface{}) ([]byte, error)
+ deserialize(src []byte, dst interface{}) error
+}
+
+// GobEncoder encodes cookie values using encoding/gob. This is the simplest
+// encoder and can handle complex types via gob.Register.
+type GobEncoder struct{}
+
+// JSONEncoder encodes cookie values using encoding/json. Users who wish to
+// encode complex types need to satisfy the json.Marshaller and
+// json.Unmarshaller interfaces.
+type JSONEncoder struct{}
+
// MaxLength restricts the maximum length, in bytes, for the cookie value.
//
// Default is 4096, which is the maximum value accepted by Internet Explorer.
@@ -123,6 +143,15 @@ func (s *SecureCookie) BlockFunc(f func([]byte) (cipher.Block, error)) *SecureCo
return s
}
+// Encoding sets the encoding/serialization method for cookies.
+//
+// Default is encoding/gob.
+func (s *SecureCookie) Encoding(e encoder) *SecureCookie {
+ s.enc = e
+
+ return s
+}
+
// Encode encodes a cookie value.
//
// It serializes, optionally encrypts, signs with a message authentication code, and
@@ -143,7 +172,7 @@ func (s *SecureCookie) Encode(name string, value interface{}) (string, error) {
var err error
var b []byte
// 1. Serialize.
- if b, err = serialize(value); err != nil {
+ if b, err = s.enc.serialize(value); err != nil {
return "", err
}
// 2. Encrypt (optional).
@@ -226,7 +255,7 @@ func (s *SecureCookie) Decode(name, value string, dst interface{}) error {
}
}
// 6. Deserialize.
- if err = deserialize(b, dst); err != nil {
+ if err = s.enc.deserialize(b, dst); err != nil {
return err
}
// Done.
@@ -301,7 +330,7 @@ func decrypt(block cipher.Block, value []byte) ([]byte, error) {
// Serialization --------------------------------------------------------------
// serialize encodes a value using gob.
-func serialize(src interface{}) ([]byte, error) {
+func (e GobEncoder) serialize(src interface{}) ([]byte, error) {
buf := new(bytes.Buffer)
enc := gob.NewEncoder(buf)
if err := enc.Encode(src); err != nil {
@@ -311,7 +340,7 @@ func serialize(src interface{}) ([]byte, error) {
}
// deserialize decodes a value using gob.
-func deserialize(src []byte, dst interface{}) error {
+func (e GobEncoder) deserialize(src []byte, dst interface{}) error {
dec := gob.NewDecoder(bytes.NewBuffer(src))
if err := dec.Decode(dst); err != nil {
return err
@@ -319,6 +348,26 @@ func deserialize(src []byte, dst interface{}) error {
return nil
}
+// serialize encodes a value using encoding/json.
+func (e JSONEncoder) serialize(src interface{}) ([]byte, error) {
+ buf := new(bytes.Buffer)
+ enc := json.NewEncoder(buf)
+ if err := enc.Encode(src); err != nil {
+ return nil, err
+ }
+
+ return buf.Bytes(), nil
+}
+
+// deserialize decodes a value using encoding/json.
+func (e JSONEncoder) deserialize(src []byte, dst interface{}) error {
+ dec := json.NewDecoder(bytes.NewBuffer(src))
+ if err := dec.Decode(dst); err != nil {
+ return err
+ }
+ return nil
+}
+
// Encoding -------------------------------------------------------------------
// encode encodes a value using base64.