Add Now function which returns UTC instead of local time.
diff --git a/.gitignore b/.gitignore
index 6289cdb..7bae159 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,4 +24,6 @@
*.prof
*.out
-*.tmp
\ No newline at end of file
+*.tmp
+tags
+
diff --git a/.tags b/.tags
deleted file mode 100644
index bb68421..0000000
--- a/.tags
+++ /dev/null
@@ -1,8 +0,0 @@
-!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
-!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
-!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
-!_TAG_PROGRAM_NAME Exuberant Ctags //
-!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
-!_TAG_PROGRAM_VERSION 5.8 //
-onChange /home/eric/gopath/src/github.com/SermoDigital/jose/cover.html /^ function onChange() {$/;" f
-onChange /home/eric/gopath/src/github.com/SermoDigital/jose/jws/cover.html /^ function onChange() {$/;" f
diff --git a/jws/cover.html b/jws/cover.html
deleted file mode 100644
index 6357801..0000000
--- a/jws/cover.html
+++ /dev/null
@@ -1,1279 +0,0 @@
-
-<!DOCTYPE html>
-<html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
- <style>
- body {
- background: black;
- color: rgb(80, 80, 80);
- }
- body, pre, #legend span {
- font-family: Menlo, monospace;
- font-weight: bold;
- }
- #topbar {
- background: black;
- position: fixed;
- top: 0; left: 0; right: 0;
- height: 42px;
- border-bottom: 1px solid rgb(80, 80, 80);
- }
- #content {
- margin-top: 50px;
- }
- #nav, #legend {
- float: left;
- margin-left: 10px;
- }
- #legend {
- margin-top: 12px;
- }
- #nav {
- margin-top: 10px;
- }
- #legend span {
- margin: 0 5px;
- }
- .cov0 { color: rgb(192, 0, 0) }
-.cov1 { color: rgb(128, 128, 128) }
-.cov2 { color: rgb(116, 140, 131) }
-.cov3 { color: rgb(104, 152, 134) }
-.cov4 { color: rgb(92, 164, 137) }
-.cov5 { color: rgb(80, 176, 140) }
-.cov6 { color: rgb(68, 188, 143) }
-.cov7 { color: rgb(56, 200, 146) }
-.cov8 { color: rgb(44, 212, 149) }
-.cov9 { color: rgb(32, 224, 152) }
-.cov10 { color: rgb(20, 236, 155) }
-
- </style>
- </head>
- <body>
- <div id="topbar">
- <div id="nav">
- <select id="files">
-
- <option value="file0">github.com/SermoDigital/jose/jws/claims.go (5.4%)</option>
-
- <option value="file1">github.com/SermoDigital/jose/jws/jws.go (66.3%)</option>
-
- <option value="file2">github.com/SermoDigital/jose/jws/jws_serialize.go (73.1%)</option>
-
- <option value="file3">github.com/SermoDigital/jose/jws/jws_validate.go (76.5%)</option>
-
- <option value="file4">github.com/SermoDigital/jose/jws/jwt.go (75.0%)</option>
-
- <option value="file5">github.com/SermoDigital/jose/jws/payload.go (81.2%)</option>
-
- <option value="file6">github.com/SermoDigital/jose/jws/rawbase64.go (100.0%)</option>
-
- <option value="file7">github.com/SermoDigital/jose/jws/signing_methods.go (84.6%)</option>
-
- </select>
- </div>
- <div id="legend">
- <span>not tracked</span>
-
- <span class="cov0">not covered</span>
- <span class="cov8">covered</span>
-
- </div>
- </div>
- <div id="content">
-
- <pre class="file" id="file0" >package jws
-
-import (
- "encoding/json"
-
- "github.com/SermoDigital/jose"
- "github.com/SermoDigital/jose/jwt"
-)
-
-// Claims represents a set of JOSE Claims.
-type Claims jwt.Claims
-
-// Get retrieves the value corresponding with key from the Claims.
-func (c Claims) Get(key string) interface{} <span class="cov8" title="1">{
- return jwt.Claims(c).Get(key)
-}</span>
-
-// Set sets Claims[key] = val. It'll overwrite without warning.
-func (c Claims) Set(key string, val interface{}) <span class="cov0" title="0">{
- jwt.Claims(c).Set(key, val)
-}</span>
-
-// Del removes the value that corresponds with key from the Claims.
-func (c Claims) Del(key string) <span class="cov0" title="0">{
- jwt.Claims(c).Del(key)
-}</span>
-
-// Has returns true if a value for the given key exists inside the Claims.
-func (c Claims) Has(key string) bool <span class="cov0" title="0">{
- return jwt.Claims(c).Has(key)
-}</span>
-
-// MarshalJSON implements json.Marshaler for Claims.
-func (c Claims) MarshalJSON() ([]byte, error) <span class="cov8" title="1">{
- return jwt.Claims(c).MarshalJSON()
-}</span>
-
-// Base64 implements the Encoder interface.
-func (c Claims) Base64() ([]byte, error) <span class="cov0" title="0">{
- return jwt.Claims(c).Base64()
-}</span>
-
-// UnmarshalJSON implements json.Unmarshaler for Claims.
-func (c *Claims) UnmarshalJSON(b []byte) error <span class="cov0" title="0">{
- if b == nil </span><span class="cov0" title="0">{
- return nil
- }</span>
-
- <span class="cov0" title="0">b, err := jose.DecodeEscaped(b)
- if err != nil </span><span class="cov0" title="0">{
- return err
- }</span>
-
- // Since json.Unmarshal calls UnmarshalJSON,
- // calling json.Unmarshal on *p would be infinitely recursive
- // A temp variable is needed because &map[string]interface{}(*p) is
- // invalid Go.
-
- <span class="cov0" title="0">tmp := map[string]interface{}(*c)
- if err = json.Unmarshal(b, &tmp); err != nil </span><span class="cov0" title="0">{
- return err
- }</span>
- <span class="cov0" title="0">*c = Claims(tmp)
- return nil</span>
-}
-
-// Issuer retrieves claim "iss" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.1
-func (c Claims) Issuer() (string, bool) <span class="cov0" title="0">{
- return jwt.Claims(c).Issuer()
-}</span>
-
-// Subject retrieves claim "sub" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.2
-func (c Claims) Subject() (string, bool) <span class="cov0" title="0">{
- return jwt.Claims(c).Subject()
-}</span>
-
-// Audience retrieves claim "aud" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.3
-func (c Claims) Audience() (interface{}, bool) <span class="cov0" title="0">{
- return jwt.Claims(c).Audience()
-}</span>
-
-// Expiration retrieves claim "exp" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.4
-func (c Claims) Expiration() (int64, bool) <span class="cov0" title="0">{
- return jwt.Claims(c).Expiration()
-}</span>
-
-// NotBefore retrieves claim "nbf" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.5
-func (c Claims) NotBefore() (int64, bool) <span class="cov0" title="0">{
- return jwt.Claims(c).NotBefore()
-}</span>
-
-// IssuedAt retrieves claim "iat" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.6
-func (c Claims) IssuedAt() (int64, bool) <span class="cov0" title="0">{
- return jwt.Claims(c).IssuedAt()
-}</span>
-
-// JWTID retrieves claim "jti" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.7
-func (c Claims) JWTID() (string, bool) <span class="cov0" title="0">{
- return jwt.Claims(c).JWTID()
-}</span>
-
-// RemoveIssuer deletes claim "iss" from c.
-func (c Claims) RemoveIssuer() <span class="cov0" title="0">{
- jwt.Claims(c).RemoveIssuer()
-}</span>
-
-// RemoveSubject deletes claim "sub" from c.
-func (c Claims) RemoveSubject() <span class="cov0" title="0">{
- jwt.Claims(c).RemoveIssuer()
-}</span>
-
-// RemoveAudience deletes claim "aud" from c.
-func (c Claims) RemoveAudience() <span class="cov0" title="0">{
- jwt.Claims(c).Audience()
-}</span>
-
-// RemoveExpiration deletes claim "exp" from c.
-func (c Claims) RemoveExpiration() <span class="cov0" title="0">{
- jwt.Claims(c).RemoveExpiration()
-}</span>
-
-// RemoveNotBefore deletes claim "nbf" from c.
-func (c Claims) RemoveNotBefore() <span class="cov0" title="0">{
- jwt.Claims(c).NotBefore()
-}</span>
-
-// RemoveIssuedAt deletes claim "iat" from c.
-func (c Claims) RemoveIssuedAt() <span class="cov0" title="0">{
- jwt.Claims(c).IssuedAt()
-}</span>
-
-// RemoveJWTID deletes claim "jti" from c.
-func (c Claims) RemoveJWTID() <span class="cov0" title="0">{
- jwt.Claims(c).RemoveJWTID()
-}</span>
-
-// SetIssuer sets claim "iss" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.1
-func (c Claims) SetIssuer(issuer string) <span class="cov0" title="0">{
- jwt.Claims(c).SetIssuer(issuer)
-}</span>
-
-// SetSubject sets claim "iss" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.2
-func (c Claims) SetSubject(subject string) <span class="cov0" title="0">{
- jwt.Claims(c).SetSubject(subject)
-}</span>
-
-// SetAudience sets claim "aud" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.3
-func (c Claims) SetAudience(audience ...string) <span class="cov0" title="0">{
- jwt.Claims(c).SetAudience(audience...)
-}</span>
-
-// SetExpiration sets claim "exp" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.4
-func (c Claims) SetExpiration(expiration int64) <span class="cov0" title="0">{
- jwt.Claims(c).SetExpiration(expiration)
-}</span>
-
-// SetNotBefore sets claim "nbf" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.5
-func (c Claims) SetNotBefore(notBefore int64) <span class="cov0" title="0">{
- jwt.Claims(c).SetNotBefore(notBefore)
-}</span>
-
-// SetIssuedAt sets claim "iat" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.6
-func (c Claims) SetIssuedAt(issuedAt int64) <span class="cov0" title="0">{
- jwt.Claims(c).SetIssuedAt(issuedAt)
-}</span>
-
-// SetJWTID sets claim "jti" per its type in
-// https://tools.ietf.org/html/rfc7519#section-4.1.7
-func (c Claims) SetJWTID(uniqueID string) <span class="cov0" title="0">{
- jwt.Claims(c).SetJWTID(uniqueID)
-}</span>
-
-var (
- _ json.Marshaler = (Claims)(nil)
- _ json.Unmarshaler = (*Claims)(nil)
-)
-</pre>
-
- <pre class="file" id="file1" style="display: none">package jws
-
-import (
- "bytes"
- "encoding/json"
-
- "github.com/SermoDigital/jose"
- "github.com/SermoDigital/jose/crypto"
-)
-
-// JWS implements a JWS per RFC 7515.
-type JWS interface {
- // Payload Returns the payload.
- Payload() interface{}
-
- // SetPayload sets the payload with the given value.
- SetPayload(interface{})
-
- // Protected returns the JWS' Protected Header.
- // i represents the index of the Protected Header.
- // Left empty, it defaults to 0.
- Protected(...int) jose.Protected
-
- // Header returns the JWS' unprotected Header.
- // i represents the index of the Protected Header.
- // Left empty, it defaults to 0.
- Header(...int) jose.Header
-
- // Verify validates the current JWS' signature as-is. Refer to
- // ValidateMulti for more information.
- Verify(key interface{}, method crypto.SigningMethod) error
-
- // ValidateMulti validates the current JWS' signature as-is. Since it's
- // meant to be called after parsing a stream of bytes into a JWS, it
- // shouldn't do any internal parsing like the Sign, Flat, Compact, or
- // General methods do.
- VerifyMulti(keys []interface{}, methods []crypto.SigningMethod, o *SigningOpts) error
-
- // VerifyCallback validates the current JWS' signature as-is. It
- // accepts a callback function that can be used to access header
- // parameters to lookup needed information. For example, looking
- // up the "kid" parameter.
- // The return slice must be a slice of keys used in the verification
- // of the JWS.
- VerifyCallback(fn VerifyCallback, methods []crypto.SigningMethod, o *SigningOpts) error
-
- // General serializes the JWS into its "general" form per
- // https://tools.ietf.org/html/rfc7515#section-7.2.1
- General(keys ...interface{}) ([]byte, error)
-
- // Flat serializes the JWS to its "flattened" form per
- // https://tools.ietf.org/html/rfc7515#section-7.2.2
- Flat(key interface{}) ([]byte, error)
-
- // Compact serializes the JWS into its "compact" form per
- // https://tools.ietf.org/html/rfc7515#section-7.1
- Compact(key interface{}) ([]byte, error)
-
- // IsJWT returns true if the JWS is a JWT.
- IsJWT() bool
-}
-
-// jws represents a specific jws.
-type jws struct {
- payload *payload
- plcache rawBase64
- clean bool
-
- sb []sigHead
-
- isJWT bool
-}
-
-// Payload returns the jws' payload.
-func (j *jws) Payload() interface{} <span class="cov8" title="1">{ return j.payload.v }</span>
-
-// SetPayload sets the jws' raw, unexported payload.
-func (j *jws) SetPayload(val interface{}) <span class="cov8" title="1">{ j.payload.v = val }</span>
-
-// Protected returns the JWS' Protected Header.
-// i represents the index of the Protected Header.
-// Left empty, it defaults to 0.
-func (j *jws) Protected(i ...int) jose.Protected <span class="cov0" title="0">{
- if len(i) == 0 </span><span class="cov0" title="0">{
- return j.sb[0].protected
- }</span>
- <span class="cov0" title="0">return j.sb[i[0]].protected</span>
-}
-
-// Header returns the JWS' unprotected Header.
-// i represents the index of the Protected Header.
-// Left empty, it defaults to 0.
-func (j *jws) Header(i ...int) jose.Header <span class="cov0" title="0">{
- if len(i) == 0 </span><span class="cov0" title="0">{
- return j.sb[0].unprotected
- }</span>
- <span class="cov0" title="0">return j.sb[i[0]].unprotected</span>
-}
-
-// sigHead represents the 'signatures' member of the jws' "general"
-// serialization form per
-// https://tools.ietf.org/html/rfc7515#section-7.2.1
-//
-// It's embedded inside the "flat" structure in order to properly
-// create the "flat" jws.
-type sigHead struct {
- Protected rawBase64 `json:"protected,omitempty"`
- Unprotected rawBase64 `json:"header,omitempty"`
- Signature crypto.Signature `json:"signature"`
-
- protected jose.Protected
- unprotected jose.Header
- clean bool
-
- method crypto.SigningMethod
-}
-
-func (s *sigHead) unmarshal() error <span class="cov8" title="1">{
- if err := s.protected.UnmarshalJSON(s.Protected); err != nil </span><span class="cov0" title="0">{
- return err
- }</span>
- <span class="cov8" title="1">if err := s.unprotected.UnmarshalJSON(s.Unprotected); err != nil </span><span class="cov0" title="0">{
- return err
- }</span>
- <span class="cov8" title="1">return nil</span>
-}
-
-// New creates a JWS with the provided crypto.SigningMethods.
-func New(content interface{}, methods ...crypto.SigningMethod) JWS <span class="cov8" title="1">{
- sb := make([]sigHead, len(methods))
- for i := range methods </span><span class="cov8" title="1">{
- sb[i] = sigHead{
- protected: jose.Protected{
- "alg": methods[i].Alg(),
- },
- unprotected: jose.Header{},
- method: methods[i],
- }
- }</span>
- <span class="cov8" title="1">return &jws{
- payload: &payload{v: content},
- sb: sb,
- }</span>
-}
-
-func (s *sigHead) assignMethod(p jose.Protected) error <span class="cov8" title="1">{
- alg, ok := p.Get("alg").(string)
- if !ok </span><span class="cov0" title="0">{
- return ErrNoAlgorithm
- }</span>
-
- <span class="cov8" title="1">sm := GetSigningMethod(alg)
- if sm == nil </span><span class="cov0" title="0">{
- return ErrNoAlgorithm
- }</span>
-
- <span class="cov8" title="1">s.method = sm
- return nil</span>
-}
-
-type generic struct {
- Payload rawBase64 `json:"payload"`
- sigHead
- Signatures []sigHead `json:"signatures,omitempty"`
-}
-
-// Parse parses any of the three serialized jws forms into a physical
-// jws per https://tools.ietf.org/html/rfc7515#section-5.2
-//
-// It accepts a json.Unmarshaler in order to properly parse
-// the payload. In order to keep the caller from having to do extra
-// parsing of the payload, a json.Unmarshaler can be passed
-// which will be then to unmarshal the payload however the caller
-// wishes. Do note that if json.Unmarshal returns an error the
-// original payload will be used as if no json.Unmarshaler was
-// passed.
-//
-// Internally, Parse applies some heuristics and then calls either
-// ParseGeneral, ParseFlat, or ParseCompact.
-// It should only be called if, for whatever reason, you do not
-// know which form the serialized JWT is in.
-//
-// It cannot parse a JWT.
-func Parse(encoded []byte, u ...json.Unmarshaler) (JWS, error) <span class="cov8" title="1">{
- // Try and unmarshal into a generic struct that'll
- // hopefully hold either of the two JSON serialization
- // formats.
- var g generic
-
- // Not valid JSON. Let's try compact.
- if err := json.Unmarshal(encoded, &g); err != nil </span><span class="cov0" title="0">{
- return ParseCompact(encoded, u...)
- }</span>
-
- <span class="cov8" title="1">if g.Signatures == nil </span><span class="cov8" title="1">{
- return g.parseFlat(u...)
- }</span>
- <span class="cov0" title="0">return g.parseGeneral(u...)</span>
-}
-
-// ParseGeneral parses a jws serialized into its "general" form per
-// https://tools.ietf.org/html/rfc7515#section-7.2.1
-// into a physical jws per
-// https://tools.ietf.org/html/rfc7515#section-5.2
-//
-// For information on the json.Unmarshaler parameter, see Parse.
-func ParseGeneral(encoded []byte, u ...json.Unmarshaler) (JWS, error) <span class="cov8" title="1">{
- var g generic
- if err := json.Unmarshal(encoded, &g); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
- <span class="cov8" title="1">return g.parseGeneral(u...)</span>
-}
-
-func (g *generic) parseGeneral(u ...json.Unmarshaler) (JWS, error) <span class="cov8" title="1">{
-
- var p payload
- if len(u) > 0 </span><span class="cov0" title="0">{
- p.u = u[0]
- }</span>
-
- <span class="cov8" title="1">if err := p.UnmarshalJSON(g.Payload); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
-
- <span class="cov8" title="1">for i := range g.Signatures </span><span class="cov8" title="1">{
- if err := g.Signatures[i].unmarshal(); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
- <span class="cov8" title="1">if err := checkHeaders(jose.Header(g.Signatures[i].protected), g.Signatures[i].unprotected); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
-
- <span class="cov8" title="1">if err := g.Signatures[i].assignMethod(g.Signatures[i].protected); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
-
- <span class="cov8" title="1">g.clean = true</span>
- }
-
- <span class="cov8" title="1">return &jws{
- payload: &p,
- plcache: g.Payload,
- clean: true,
- sb: g.Signatures,
- }, nil</span>
-}
-
-// ParseFlat parses a jws serialized into its "flat" form per
-// https://tools.ietf.org/html/rfc7515#section-7.2.2
-// into a physical jws per
-// https://tools.ietf.org/html/rfc7515#section-5.2
-//
-// For information on the json.Unmarshaler parameter, see Parse.
-func ParseFlat(encoded []byte, u ...json.Unmarshaler) (JWS, error) <span class="cov8" title="1">{
- var g generic
- if err := json.Unmarshal(encoded, &g); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
- <span class="cov8" title="1">return g.parseFlat(u...)</span>
-}
-
-func (g *generic) parseFlat(u ...json.Unmarshaler) (JWS, error) <span class="cov8" title="1">{
-
- var p payload
- if len(u) > 0 </span><span class="cov8" title="1">{
- p.u = u[0]
- }</span>
-
- <span class="cov8" title="1">if err := p.UnmarshalJSON(g.Payload); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
-
- <span class="cov8" title="1">if err := g.sigHead.unmarshal(); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
- <span class="cov8" title="1">g.sigHead.clean = true
-
- if err := checkHeaders(jose.Header(g.sigHead.protected), g.sigHead.unprotected); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
-
- <span class="cov8" title="1">if err := g.sigHead.assignMethod(g.sigHead.protected); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
-
- <span class="cov8" title="1">return &jws{
- payload: &p,
- plcache: g.Payload,
- clean: true,
- sb: []sigHead{g.sigHead},
- }, nil</span>
-}
-
-// ParseCompact parses a jws serialized into its "compact" form per
-// https://tools.ietf.org/html/rfc7515#section-7.1
-// into a physical jws per
-// https://tools.ietf.org/html/rfc7515#section-5.2
-//
-// For information on the json.Unmarshaler parameter, see Parse.
-func ParseCompact(encoded []byte, u ...json.Unmarshaler) (JWS, error) <span class="cov8" title="1">{
- return parseCompact(encoded, false)
-}</span>
-
-func parseCompact(encoded []byte, jwt bool) (*jws, error) <span class="cov8" title="1">{
-
- // This section loosely follows
- // https://tools.ietf.org/html/rfc7519#section-7.2
- // because it's used to parse _both_ jws and JWTs.
-
- parts := bytes.Split(encoded, []byte{'.'})
- if len(parts) != 3 </span><span class="cov0" title="0">{
- return nil, ErrNotCompact
- }</span>
-
- <span class="cov8" title="1">var p jose.Protected
- if err := p.UnmarshalJSON(parts[0]); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
-
- <span class="cov8" title="1">s := sigHead{
- Protected: parts[0],
- protected: p,
- Signature: parts[2],
- clean: true,
- }
-
- if err := s.assignMethod(p); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
-
- <span class="cov8" title="1">j := jws{
- payload: &payload{},
- plcache: parts[1],
- sb: []sigHead{s},
- isJWT: jwt,
- }
-
- if err := j.payload.UnmarshalJSON(parts[1]); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
-
- <span class="cov8" title="1">j.clean = true
-
- if err := j.sb[0].Signature.UnmarshalJSON(parts[2]); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
-
- // https://tools.ietf.org/html/rfc7519#section-7.2.8
- <span class="cov8" title="1">cty, ok := p.Get("cty").(string)
- if ok && cty == "JWT" </span><span class="cov0" title="0">{
- return &j, ErrHoldsJWE
- }</span>
- <span class="cov8" title="1">return &j, nil</span>
-}
-
-// IgnoreDupes should be set to true if the internal duplicate header key check
-// should ignore duplicate Header keys instead of reporting an error when
-// duplicate Header keys are found.
-//
-// Note:
-// Duplicate Header keys are defined in
-// https://tools.ietf.org/html/rfc7515#section-5.2
-// meaning keys that both the protected and unprotected
-// Headers possess.
-var IgnoreDupes bool
-
-// checkHeaders returns an error per the constraints described in
-// IgnoreDupes' comment.
-func checkHeaders(a, b jose.Header) error <span class="cov8" title="1">{
- if len(a)+len(b) == 0 </span><span class="cov0" title="0">{
- return ErrTwoEmptyHeaders
- }</span>
- <span class="cov8" title="1">for key := range a </span><span class="cov8" title="1">{
- if b.Has(key) && !IgnoreDupes </span><span class="cov0" title="0">{
- return ErrDuplicateHeaderParameter
- }</span>
- }
- <span class="cov8" title="1">return nil</span>
-}
-
-var _ JWS = (*jws)(nil)
-</pre>
-
- <pre class="file" id="file2" style="display: none">package jws
-
-import (
- "bytes"
- "encoding/json"
-)
-
-// Flat serializes the JWS to its "flattened" form per
-// https://tools.ietf.org/html/rfc7515#section-7.2.2
-func (j *jws) Flat(key interface{}) ([]byte, error) <span class="cov8" title="1">{
- if len(j.sb) < 1 </span><span class="cov0" title="0">{
- return nil, ErrNotEnoughMethods
- }</span>
- <span class="cov8" title="1">if err := j.sign(key); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
- <span class="cov8" title="1">return json.Marshal(struct {
- Payload rawBase64 `json:"payload"`
- sigHead
- }{
- Payload: j.plcache,
- sigHead: j.sb[0],
- })</span>
-}
-
-// General serializes the JWS into its "general" form per
-// https://tools.ietf.org/html/rfc7515#section-7.2.1
-//
-// If only one key is passed it's used for all the provided
-// crypto.SigningMethods. Otherwise, len(keys) must equal the number
-// of crypto.SigningMethods added.
-func (j *jws) General(keys ...interface{}) ([]byte, error) <span class="cov8" title="1">{
- if err := j.sign(keys...); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
- <span class="cov8" title="1">return json.Marshal(struct {
- Payload rawBase64 `json:"payload"`
- Signatures []sigHead `json:"signatures"`
- }{
- Payload: j.plcache,
- Signatures: j.sb,
- })</span>
-}
-
-// Compact serializes the JWS into its "compact" form per
-// https://tools.ietf.org/html/rfc7515#section-7.1
-func (j *jws) Compact(key interface{}) ([]byte, error) <span class="cov8" title="1">{
- if len(j.sb) < 1 </span><span class="cov0" title="0">{
- return nil, ErrNotEnoughMethods
- }</span>
-
- <span class="cov8" title="1">if err := j.sign(key); err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
-
- <span class="cov8" title="1">sig, err := j.sb[0].Signature.Base64()
- if err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
- <span class="cov8" title="1">return format(
- j.sb[0].Protected,
- j.plcache,
- sig,
- ), nil</span>
-}
-
-// sign signs each index of j's sb member.
-func (j *jws) sign(keys ...interface{}) error <span class="cov8" title="1">{
- if err := j.cache(); err != nil </span><span class="cov0" title="0">{
- return err
- }</span>
-
- <span class="cov8" title="1">if len(keys) < 1 ||
- len(keys) > 1 && len(keys) != len(j.sb) </span><span class="cov0" title="0">{
- return ErrNotEnoughKeys
- }</span>
-
- <span class="cov8" title="1">if len(keys) == 1 </span><span class="cov8" title="1">{
- k := keys[0]
- keys = make([]interface{}, len(j.sb))
- for i := range keys </span><span class="cov8" title="1">{
- keys[i] = k
- }</span>
- }
-
- <span class="cov8" title="1">for i := range j.sb </span><span class="cov8" title="1">{
- if err := j.sb[i].cache(); err != nil </span><span class="cov0" title="0">{
- return err
- }</span>
-
- <span class="cov8" title="1">raw := format(j.sb[i].Protected, j.plcache)
- sig, err := j.sb[i].method.Sign(raw, keys[i])
- if err != nil </span><span class="cov0" title="0">{
- return err
- }</span>
- <span class="cov8" title="1">j.sb[i].Signature = sig</span>
- }
-
- <span class="cov8" title="1">return nil</span>
-}
-
-// cache marshals the payload, but only if it's changed since the last cache.
-func (j *jws) cache() error <span class="cov8" title="1">{
- if !j.clean </span><span class="cov8" title="1">{
- var err error
- j.plcache, err = j.payload.Base64()
- j.clean = err == nil
- return err
- }</span>
- <span class="cov0" title="0">return nil</span>
-}
-
-// cache marshals the protected and unprotected headers, but only if
-// they've changed since their last cache.
-func (s *sigHead) cache() error <span class="cov8" title="1">{
- if !s.clean </span><span class="cov8" title="1">{
- var err error
-
- s.Protected, err = s.protected.Base64()
- if err != nil </span><span class="cov0" title="0">{
- goto err_return</span>
- }
-
- <span class="cov8" title="1">s.Unprotected, err = s.unprotected.Base64()
- if err != nil </span><span class="cov0" title="0">{
- goto err_return</span>
- }
-
- <span class="cov8" title="1">err_return:
- s.clean = err == nil
- return err</span>
- }
- <span class="cov0" title="0">return nil</span>
-}
-
-// format formats a slice of bytes in the order given, joining
-// them with a period.
-func format(a ...[]byte) []byte <span class="cov8" title="1">{
- return bytes.Join(a, []byte{'.'})
-}</span>
-</pre>
-
- <pre class="file" id="file3" style="display: none">package jws
-
-import (
- "fmt"
-
- "github.com/SermoDigital/jose/crypto"
-)
-
-// VerifyCallback is a callback function that can be used to access header
-// parameters to lookup needed information. For example, looking
-// up the "kid" parameter.
-// The return slice must be a slice of keys used in the verification
-// of the JWS.
-type VerifyCallback func(JWS) ([]interface{}, error)
-
-// VerifyCallback validates the current JWS' signature as-is. It
-// accepts a callback function that can be used to access header
-// parameters to lookup needed information. For example, looking
-// up the "kid" parameter.
-// The return slice must be a slice of keys used in the verification
-// of the JWS.
-func (j *jws) VerifyCallback(fn VerifyCallback, methods []crypto.SigningMethod, o *SigningOpts) error <span class="cov8" title="1">{
- keys, err := fn(j)
- if err != nil </span><span class="cov8" title="1">{
- return err
- }</span>
- <span class="cov8" title="1">return j.VerifyMulti(keys, methods, o)</span>
-}
-
-// IsMultiError returns true if the given error is type MultiError.
-func IsMultiError(err error) bool <span class="cov0" title="0">{
- _, ok := err.(MultiError)
- return ok
-}</span>
-
-// MultiError is a slice of errors.
-type MultiError []error
-
-func (m MultiError) sanityCheck() error <span class="cov8" title="1">{
- if m == nil </span><span class="cov8" title="1">{
- return nil
- }</span>
- <span class="cov8" title="1">return m</span>
-}
-
-// Errors implements the error interface.
-func (m MultiError) Error() string <span class="cov0" title="0">{
- s, n := "", 0
- for _, e := range m </span><span class="cov0" title="0">{
- if e != nil </span><span class="cov0" title="0">{
- if n == 0 </span><span class="cov0" title="0">{
- s = e.Error()
- }</span>
- <span class="cov0" title="0">n++</span>
- }
- }
- <span class="cov0" title="0">switch n </span>{
- <span class="cov0" title="0">case 0:
- return "(0 errors)"</span>
- <span class="cov0" title="0">case 1:
- return s</span>
- <span class="cov0" title="0">case 2:
- return s + " (and 1 other error)"</span>
- }
- <span class="cov0" title="0">return fmt.Sprintf("%s (and %d other errors)", s, n-1)</span>
-}
-
-// Any means any of the JWS signatures need to verify.
-// Refer to verifyMulti for more information.
-const Any int = 0
-
-// VerifyMulti verifies the current JWS as-is. Since it's meant to be
-// called after parsing a stream of bytes into a JWS, it doesn't do any
-// internal parsing like the Sign, Flat, Compact, or General methods do.
-func (j *jws) VerifyMulti(keys []interface{}, methods []crypto.SigningMethod, o *SigningOpts) error <span class="cov8" title="1">{
-
- // Catch a simple mistake. Parameter o is irrelevant in this scenario.
- if len(keys) == 1 &&
- len(methods) == 1 &&
- len(j.sb) == 1 </span><span class="cov8" title="1">{
- return j.Verify(keys[0], methods[0])
- }</span>
-
- <span class="cov8" title="1">if len(j.sb) != len(methods) </span><span class="cov8" title="1">{
- return ErrNotEnoughMethods
- }</span>
-
- <span class="cov8" title="1">if len(keys) < 1 ||
- len(keys) > 1 && len(keys) != len(j.sb) </span><span class="cov8" title="1">{
- return ErrNotEnoughKeys
- }</span>
-
- // TODO do this better.
- <span class="cov8" title="1">if len(keys) == 1 </span><span class="cov8" title="1">{
- k := keys[0]
- keys = make([]interface{}, len(methods))
- for i := range keys </span><span class="cov8" title="1">{
- keys[i] = k
- }</span>
- }
-
- <span class="cov8" title="1">var o2 SigningOpts
- if o == nil </span><span class="cov8" title="1">{
- o = &SigningOpts{}
- }</span>
-
- <span class="cov8" title="1">var m MultiError
- for i := range j.sb </span><span class="cov8" title="1">{
- err := j.sb[i].verify(j.plcache, keys[i], methods[i])
- if err != nil </span><span class="cov8" title="1">{
- m = append(m, err)
- }</span><span class="cov8" title="1"> else {
- o2.Inc()
- if o.Needs(i) </span><span class="cov8" title="1">{
- o2.Append(i)
- }</span>
- }
- }
-
- <span class="cov8" title="1">if err := o.Validate(&o2); err != nil </span><span class="cov8" title="1">{
- return err
- }</span>
- <span class="cov8" title="1">return m.sanityCheck()</span>
-}
-
-// SigningOpts is a struct which holds options for validating
-// JWS signatures.
-// Number represents the cumulative which signatures need to verify
-// in order for the JWS to be considered valid.
-// Leave 'Number' empty or set it to the constant 'Any' if any number of
-// valid signatures (greater than one) should verify the JWS.
-//
-// Use the indices of the signatures that need to verify in order
-// for the JWS to be considered valid if specific signatures need
-// to verify in order for the JWS to be considered valid.
-//
-// Note:
-// The JWS spec requires *at least* one
-// signature to verify in order for the JWS to be considered valid.
-type SigningOpts struct {
- // Minimum of signatures which need to verify.
- Number int
-
- // Indices of specific signatures which need to verify.
- Indices []int
- ptr int
-
- _ struct{}
-}
-
-// Append appends x to s's Indices member.
-func (s *SigningOpts) Append(x int) <span class="cov8" title="1">{
- s.Indices = append(s.Indices, x)
-}</span>
-
-// Needs returns true if x resides inside s's Indices member
-// for the given index. If true, it increments s's internal
-// index. It's used to match two SigningOpts Indices members.
-func (s *SigningOpts) Needs(x int) bool <span class="cov8" title="1">{
- if s.ptr < len(s.Indices) &&
- s.Indices[s.ptr] == x </span><span class="cov8" title="1">{
- s.ptr++
- return true
- }</span>
- <span class="cov8" title="1">return false</span>
-}
-
-// Inc increments s's Number member by one.
-func (s *SigningOpts) Inc() <span class="cov8" title="1">{ s.Number++ }</span>
-
-// Validate returns any errors found while validating the
-// provided SigningOpts. The receiver validates the parameter `have`.
-// It'll return an error if the passed SigningOpts' Number member is less
-// than s's or if the passed SigningOpts' Indices slice isn't equal to s's.
-func (s *SigningOpts) Validate(have *SigningOpts) error <span class="cov8" title="1">{
- if have.Number < s.Number ||
- (s.Indices != nil &&
- !eq(s.Indices, have.Indices)) </span><span class="cov8" title="1">{
- return ErrNotEnoughValidSignatures
- }</span>
- <span class="cov8" title="1">return nil</span>
-}
-
-func eq(a, b []int) bool <span class="cov8" title="1">{
- if a == nil && b == nil </span><span class="cov0" title="0">{
- return true
- }</span>
- <span class="cov8" title="1">if a == nil || b == nil || len(a) != len(b) </span><span class="cov0" title="0">{
- return false
- }</span>
- <span class="cov8" title="1">for i := range a </span><span class="cov8" title="1">{
- if a[i] != b[i] </span><span class="cov0" title="0">{
- return false
- }</span>
- }
- <span class="cov8" title="1">return true</span>
-}
-
-// Verify verifies the current JWS as-is. Refer to verifyMulti
-// for more information.
-func (j *jws) Verify(key interface{}, method crypto.SigningMethod) error <span class="cov8" title="1">{
- if len(j.sb) < 1 </span><span class="cov8" title="1">{
- return ErrCannotValidate
- }</span>
- <span class="cov8" title="1">return j.sb[0].verify(j.plcache, key, method)</span>
-}
-
-func (s *sigHead) verify(pl []byte, key interface{}, method crypto.SigningMethod) error <span class="cov8" title="1">{
- if s.method != method </span><span class="cov8" title="1">{
- return ErrMismatchedAlgorithms
- }</span>
- <span class="cov8" title="1">return method.Verify(format(s.Protected, pl), s.Signature, key)</span>
-}
-</pre>
-
- <pre class="file" id="file4" style="display: none">package jws
-
-import (
- "time"
-
- "github.com/SermoDigital/jose/crypto"
- "github.com/SermoDigital/jose/jwt"
-)
-
-// NewJWT creates a new JWT with the given claims.
-func NewJWT(claims Claims, method crypto.SigningMethod) jwt.JWT <span class="cov8" title="1">{
- j := New(claims, method).(*jws)
- j.isJWT = true
- return j
-}</span>
-
-// Serialize helps implements jwt.JWT.
-func (j *jws) Serialize(key interface{}) ([]byte, error) <span class="cov8" title="1">{
- if j.isJWT </span><span class="cov8" title="1">{
- return j.Compact(key)
- }</span>
- <span class="cov0" title="0">return nil, ErrIsNotJWT</span>
-}
-
-// Claims helps implements jwt.JWT.
-func (j *jws) Claims() jwt.Claims <span class="cov8" title="1">{
- if j.isJWT </span><span class="cov8" title="1">{
- if c, ok := j.payload.v.(Claims); ok </span><span class="cov8" title="1">{
- return jwt.Claims(c)
- }</span>
- }
- <span class="cov0" title="0">return nil</span>
-}
-
-// ParseJWT parses a serialized jwt.JWT into a physical jwt.JWT.
-// If its payload isn't a set of claims (or able to be coerced into
-// a set of claims) it'll return an error stating the
-// JWT isn't a JWT.
-func ParseJWT(encoded []byte) (jwt.JWT, error) <span class="cov8" title="1">{
- t, err := parseCompact(encoded, true)
- if err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
- <span class="cov8" title="1">c, ok := t.Payload().(map[string]interface{})
- if !ok </span><span class="cov0" title="0">{
- return nil, ErrIsNotJWT
- }</span>
- <span class="cov8" title="1">t.SetPayload(Claims(c))
- return t, nil</span>
-}
-
-// IsJWT returns true if the JWS is a JWT.
-func (j *jws) IsJWT() bool <span class="cov0" title="0">{ return j.isJWT }</span>
-
-func (j *jws) Validate(key interface{}, m crypto.SigningMethod, v ...*jwt.Validator) error <span class="cov8" title="1">{
- if j.isJWT </span><span class="cov8" title="1">{
- if err := j.Verify(key, m); err != nil </span><span class="cov0" title="0">{
- return err
- }</span>
- <span class="cov8" title="1">var v1 jwt.Validator
- if len(v) > 0 </span><span class="cov8" title="1">{
- v1 = *v[0]
- }</span>
- <span class="cov8" title="1">c, ok := j.payload.v.(Claims)
- if ok </span><span class="cov8" title="1">{
- if err := v1.Validate(j); err != nil </span><span class="cov0" title="0">{
- return err
- }</span>
- <span class="cov8" title="1">return jwt.Claims(c).Validate(time.Now().Unix(), v1.EXP, v1.NBF)</span>
- }
- }
- <span class="cov0" title="0">return ErrIsNotJWT</span>
-}
-
-// Conv converts a func(Claims) error to type jwt.ValidateFunc.
-func Conv(fn func(Claims) error) jwt.ValidateFunc <span class="cov8" title="1">{
- if fn == nil </span><span class="cov0" title="0">{
- return nil
- }</span>
- <span class="cov8" title="1">return func(c jwt.Claims) error </span><span class="cov8" title="1">{
- return fn(Claims(c))
- }</span>
-}
-
-// NewValidator returns a pointer to a jwt.Validator structure containing
-// the info to be used in the validation of a JWT.
-func NewValidator(c Claims, exp, nbf int64, fn func(Claims) error) *jwt.Validator <span class="cov8" title="1">{
- return &jwt.Validator{
- Expected: jwt.Claims(c),
- EXP: exp,
- NBF: nbf,
- Fn: Conv(fn),
- }
-}</span>
-
-var _ jwt.JWT = (*jws)(nil)
-</pre>
-
- <pre class="file" id="file5" style="display: none">package jws
-
-import (
- "encoding/json"
-
- "github.com/SermoDigital/jose"
-)
-
-// payload represents the payload of a JWS.
-type payload struct {
- v interface{}
- u json.Unmarshaler
- _ struct{}
-}
-
-// MarshalJSON implements json.Marshaler for payload.
-func (p *payload) MarshalJSON() ([]byte, error) <span class="cov8" title="1">{
- b, err := json.Marshal(p.v)
- if err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
- <span class="cov8" title="1">return jose.EncodeEscape(b), nil</span>
-}
-
-// Base64 implements jose.Encoder.
-func (p *payload) Base64() ([]byte, error) <span class="cov8" title="1">{
- b, err := json.Marshal(p.v)
- if err != nil </span><span class="cov0" title="0">{
- return nil, err
- }</span>
- <span class="cov8" title="1">return jose.Base64Encode(b), nil</span>
-}
-
-// MarshalJSON implements json.Unmarshaler for payload.
-func (p *payload) UnmarshalJSON(b []byte) error <span class="cov8" title="1">{
- b2, err := jose.DecodeEscaped(b)
- if err != nil </span><span class="cov0" title="0">{
- return err
- }</span>
-
- <span class="cov8" title="1">if p.u != nil </span><span class="cov8" title="1">{
- err := p.u.UnmarshalJSON(b2)
- p.v = p.u
- return err
- }</span>
-
- <span class="cov8" title="1">return json.Unmarshal(b2, &p.v)</span>
-}
-
-var (
- _ json.Marshaler = (*payload)(nil)
- _ json.Unmarshaler = (*payload)(nil)
- _ jose.Encoder = (*payload)(nil)
-)
-</pre>
-
- <pre class="file" id="file6" style="display: none">package jws
-
-import "encoding/json"
-
-type rawBase64 []byte
-
-// MarshalJSON implements json.Marshaler for rawBase64.
-func (r rawBase64) MarshalJSON() ([]byte, error) <span class="cov8" title="1">{
- buf := make([]byte, len(r)+2)
- buf[0] = '"'
- copy(buf[1:], r)
- buf[len(buf)-1] = '"'
- return buf, nil
-}</span>
-
-// MarshalJSON implements json.Unmarshaler for rawBase64.
-func (r *rawBase64) UnmarshalJSON(b []byte) error <span class="cov8" title="1">{
- if len(b) > 1 && b[0] == '"' && b[len(b)-1] == '"' </span><span class="cov8" title="1">{
- b = b[1 : len(b)-1]
- }</span>
- <span class="cov8" title="1">*r = rawBase64(b)
- return nil</span>
-}
-
-var (
- _ json.Marshaler = (rawBase64)(nil)
- _ json.Unmarshaler = (*rawBase64)(nil)
-)
-</pre>
-
- <pre class="file" id="file7" style="display: none">package jws
-
-import (
- "sync"
-
- "github.com/SermoDigital/jose/crypto"
-)
-
-var (
- mu = &sync.RWMutex{}
-
- signingMethods = map[string]crypto.SigningMethod{
- crypto.SigningMethodES256.Alg(): crypto.SigningMethodES256,
- crypto.SigningMethodES384.Alg(): crypto.SigningMethodES384,
- crypto.SigningMethodES512.Alg(): crypto.SigningMethodES512,
-
- crypto.SigningMethodPS256.Alg(): crypto.SigningMethodPS256,
- crypto.SigningMethodPS384.Alg(): crypto.SigningMethodPS384,
- crypto.SigningMethodPS512.Alg(): crypto.SigningMethodPS512,
-
- crypto.SigningMethodRS256.Alg(): crypto.SigningMethodRS256,
- crypto.SigningMethodRS384.Alg(): crypto.SigningMethodRS384,
- crypto.SigningMethodRS512.Alg(): crypto.SigningMethodRS512,
-
- crypto.SigningMethodHS256.Alg(): crypto.SigningMethodHS256,
- crypto.SigningMethodHS384.Alg(): crypto.SigningMethodHS384,
- crypto.SigningMethodHS512.Alg(): crypto.SigningMethodHS512,
-
- crypto.Unsecured.Alg(): crypto.Unsecured,
- }
-)
-
-// RegisterSigningMethod registers the crypto.SigningMethod in the global map.
-// This is typically done inside the caller's init function.
-func RegisterSigningMethod(sm crypto.SigningMethod) <span class="cov8" title="1">{
- if GetSigningMethod(sm.Alg()) != nil </span><span class="cov0" title="0">{
- panic("jose/jws: cannot duplicate signing methods")</span>
- }
-
- <span class="cov8" title="1">if !sm.Hasher().Available() </span><span class="cov0" title="0">{
- panic("jose/jws: specific hash is unavailable")</span>
- }
-
- <span class="cov8" title="1">mu.Lock()
- signingMethods[sm.Alg()] = sm
- mu.Unlock()</span>
-}
-
-// RemoveSigningMethod removes the crypto.SigningMethod from the global map.
-func RemoveSigningMethod(sm crypto.SigningMethod) <span class="cov8" title="1">{
- mu.Lock()
- delete(signingMethods, sm.Alg())
- mu.Unlock()
-}</span>
-
-// GetSigningMethod retrieves a crypto.SigningMethod from the global map.
-func GetSigningMethod(alg string) crypto.SigningMethod <span class="cov8" title="1">{
- mu.RLock()
- defer mu.RUnlock()
- return signingMethods[alg]
-}</span>
-</pre>
-
- </div>
- </body>
- <script>
- (function() {
- var files = document.getElementById('files');
- var visible = document.getElementById('file0');
- files.addEventListener('change', onChange, false);
- function onChange() {
- visible.style.display = 'none';
- visible = document.getElementById(files.value);
- visible.style.display = 'block';
- window.scrollTo(0, 0);
- }
- })();
- </script>
-</html>
diff --git a/jws/jwt.go b/jws/jwt.go
index 29b75b8..53da1fc 100644
--- a/jws/jwt.go
+++ b/jws/jwt.go
@@ -4,6 +4,7 @@
"net/http"
"time"
+ "github.com/SermoDigital/jose"
"github.com/SermoDigital/jose/crypto"
"github.com/SermoDigital/jose/jwt"
)
@@ -85,7 +86,7 @@
if err := v1.Validate(j); err != nil {
return err
}
- return jwt.Claims(c).Validate(time.Now(), v1.EXP, v1.NBF)
+ return jwt.Claims(c).Validate(jose.Now(), v1.EXP, v1.NBF)
}
}
return ErrIsNotJWT
diff --git a/jwt/claims.go b/jwt/claims.go
index ae41e7d..d3d93bf 100644
--- a/jwt/claims.go
+++ b/jwt/claims.go
@@ -2,7 +2,6 @@
import (
"encoding/json"
- "reflect"
"time"
"github.com/SermoDigital/jose"
@@ -234,33 +233,33 @@
c.Set("jti", uniqueID)
}
-// zero pre-allocs the zero-time value
-var zero = time.Time{}
-
-// GetTime returns a UNIX time for the given key.
+// GetTime returns a Unix timestamp for the given key.
//
-// It converts an int, int32, int64, uint, uint32, uint64 or float64 value
-// into a UNIX time (epoch seconds). float32 does not have sufficient
-// precision to store a UNIX time.
+// It converts an int, int32, int64, uint, uint32, uint64 or float64 into a Unix
+// timestamp (epoch seconds). float32 does not have sufficient precision to
+// store a Unix timestamp.
//
// Numeric values parsed from JSON will always be stored as float64 since
-// Claims is a map[string]interface{}. However, internally the values may be
-// stored directly in the claims map as different types.
+// Claims is a map[string]interface{}. However, the values may be stored directly
+// in the claims as a different type.
func (c Claims) GetTime(key string) (time.Time, bool) {
- x := c.Get(key)
- if x == nil {
- return zero, false
- }
- v := reflect.ValueOf(x)
- switch v.Kind() {
- case reflect.Int, reflect.Int32, reflect.Int64:
- return time.Unix(v.Int(), 0), true
- case reflect.Uint, reflect.Uint32, reflect.Uint64:
- return time.Unix(int64(v.Uint()), 0), true
- case reflect.Float64:
- return time.Unix(int64(v.Float()), 0), true
+ switch t := c.Get(key).(type) {
+ case int:
+ return time.Unix(int64(t), 0), true
+ case int32:
+ return time.Unix(int64(t), 0), true
+ case int64:
+ return time.Unix(int64(t), 0), true
+ case uint:
+ return time.Unix(int64(t), 0), true
+ case uint32:
+ return time.Unix(int64(t), 0), true
+ case uint64:
+ return time.Unix(int64(t), 0), true
+ case float64:
+ return time.Unix(int64(t), 0), true
default:
- return zero, false
+ return time.Time{}, false
}
}
diff --git a/time.go b/time.go
new file mode 100644
index 0000000..f366a7a
--- /dev/null
+++ b/time.go
@@ -0,0 +1,6 @@
+package jose
+
+import "time"
+
+// Now returns the current time in UTC.
+func Now() time.Time { return time.Now().UTC() }