@@ -20,17 +20,18 @@ const (
2020
2121var (
2222 errInvalidToken = errors .New ("invalid token" )
23+ errCannotParseToken = errors .New ("cannot parse token" )
2324 errNoPrivateKey = errors .New ("no private key" )
2425 tokenCharacters = []byte ("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" )
2526 pluginPrefix = "P"
26- enhancedTokenPrefix = "gtfy_ "
27+ enhancedTokenPrefix = "gtfy "
2728
2829 randReader = rand .Reader
2930)
3031
3132type EnhancedToken struct {
3233 ident string // a shared identifier, in formats like A12 for application ID 12
33- pubOrPrivKey []byte // public key
34+ pubOrPrivKey []byte
3435 timestamp int64
3536 signature []byte
3637}
@@ -51,7 +52,7 @@ func (c *EnhancedToken) Sign(timestamp int64) (*EnhancedToken, error) {
5152 }
5253 privKey := ed25519 .NewKeyFromSeed (c .pubOrPrivKey )
5354 sha512 := sha512 .New ()
54- sha512 .Write ([]byte ("iss =" ))
55+ sha512 .Write ([]byte ("iat =" ))
5556 fmt .Fprintf (sha512 , "%d" , timestamp )
5657 sign , err := privKey .Sign (nil , sha512 .Sum (nil ), crypto .SHA512 )
5758 if err != nil {
@@ -107,49 +108,49 @@ func NewEnhancedToken(ident string) *EnhancedToken {
107108func ParseEnhancedToken (token string ) (* EnhancedToken , error ) {
108109 token , found := strings .CutPrefix (token , enhancedTokenPrefix )
109110 if ! found {
110- return nil , errInvalidToken
111+ return nil , fmt . Errorf ( "%w: token must start with %s" , errCannotParseToken , enhancedTokenPrefix )
111112 }
112113
113114 // count number of dots, one dot -> ident then private key, three dots -> ident, public key, challenge then signature
114115 fields := strings .SplitN (token , "." , 4 )
115116 if len (fields ) != 2 && len (fields ) != 4 {
116- return nil , errInvalidToken
117+ return nil , fmt . Errorf ( "%w: token must have 2 or 4 fields separated by dots" , errCannotParseToken )
117118 }
118119 ident := fields [0 ]
119120 pkOrPubkeyB64 := fields [1 ]
120121 pkOrPubkeyBytesLen := base64 .RawURLEncoding .DecodedLen (len (pkOrPubkeyB64 ))
121122 pkOrPubkey , err := base64 .RawURLEncoding .DecodeString (pkOrPubkeyB64 )
122123 if err != nil {
123- return nil , errInvalidToken
124+ return nil , fmt . Errorf ( "%w: base64 decode failed: %w" , errCannotParseToken , err )
124125 }
125126 if len (fields ) == 2 {
126127 if pkOrPubkeyBytesLen != ed25519 .SeedSize {
127- return nil , errInvalidToken
128+ return nil , fmt . Errorf ( "%w: private key must be %d bytes" , errCannotParseToken , ed25519 . SeedSize )
128129 }
129130 return & EnhancedToken {
130131 ident : ident ,
131132 pubOrPrivKey : pkOrPubkey ,
132133 }, nil
133134 }
134135 if pkOrPubkeyBytesLen != ed25519 .PublicKeySize {
135- return nil , errInvalidToken
136+ return nil , fmt . Errorf ( "%w: public key must be %d bytes" , errCannotParseToken , ed25519 . PublicKeySize )
136137 }
137138 timestampStr := fields [2 ]
138139 timestamp , err := strconv .ParseInt (timestampStr , 10 , 64 )
139140 if err != nil {
140- return nil , errInvalidToken
141+ return nil , fmt . Errorf ( "%w: timestamp must be an integer: %w" , errCannotParseToken , err )
141142 }
142143 signatureB64 := fields [3 ]
143144 signatureBytesLen := base64 .RawURLEncoding .DecodedLen (len (signatureB64 ))
144145 if signatureBytesLen != ed25519 .SignatureSize {
145- return nil , errInvalidToken
146+ return nil , fmt . Errorf ( "%w: signature must be %d bytes" , errCannotParseToken , ed25519 . SignatureSize )
146147 }
147148 signature , err := base64 .RawURLEncoding .DecodeString (signatureB64 )
148149 if err != nil {
149- return nil , errInvalidToken
150+ return nil , fmt . Errorf ( "%w: base64 decode failed: %w" , errCannotParseToken , err )
150151 }
151152 sha512 := sha512 .New ()
152- sha512 .Write ([]byte ("iss =" )) // query-like encoding to give us some semantic headroom should we need more fields in the future
153+ sha512 .Write ([]byte ("iat =" )) // query-like encoding to give us some semantic headroom should we need more fields in the future
153154 fmt .Fprintf (sha512 , "%d" , timestamp )
154155 if err := ed25519 .VerifyWithOptions (pkOrPubkey , sha512 .Sum (nil ), signature , & ed25519.Options {Hash : crypto .SHA512 }); err != nil {
155156 return nil , errInvalidToken
@@ -173,13 +174,13 @@ func randIntn(n int) int {
173174
174175// GenerateApplicationToken generates an application token.
175176func GenerateApplicationToken () (publicForm , privateForm string ) {
176- token := NewEnhancedToken ("app " )
177+ token := NewEnhancedToken ("a " )
177178 return token .PublicForm (), token .String ()
178179}
179180
180181// GenerateClientToken generates a client token.
181182func GenerateClientToken () (publicForm , privateForm string ) {
182- token := NewEnhancedToken ("client " )
183+ token := NewEnhancedToken ("c " )
183184 return token .PublicForm (), token .String ()
184185}
185186
0 commit comments