diff options
author | Matt Silverlock <matt@eatsleeprepeat.net> | 2015-05-16 20:50:49 +0300 |
---|---|---|
committer | Matt Silverlock <matt@eatsleeprepeat.net> | 2015-05-16 20:50:49 +0300 |
commit | 978e3ebadae78bf30fec1524c0a264e1b8190d2e (patch) | |
tree | 4ba7a6267f45db1a27c06b110405541a41178454 /securecookie.go | |
parent | 8e98dd730fc43f1383f19615db6f2e702c9738e8 (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.go | 57 |
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. |