1+ #!/usr/bin/env python
2+ import optparse
3+ import jwt
4+ import sys
5+ import json
6+ import time
7+
8+ __prog__ = 'jwt'
9+ __version__ = '0.1'
10+
11+ def fix_optionparser_whitespace (input ):
12+ """Hacks around whitespace Nazi-ism in OptionParser"""
13+ newline = ' ' * 80
14+ doublespace = '\033 [8m.\033 [0m' * 2
15+ return input .replace (' ' , doublespace ).replace ('\n ' , newline )
16+
17+
18+
19+ def main ():
20+ """Encodes or decodes JSON Web Tokens based on input
21+
22+ Decoding examples:
23+
24+ %prog --key=secret json.web.token
25+ %prog --no-verify json.web.token
26+
27+ Encoding requires the key argument and takes space separated key/value pairs
28+ separated by equals (=) as input. Examples:
29+
30+ %prog --key=secret iss=me exp=1302049071
31+ %prog --key=secret foo=bar exp=+10
32+
33+ The exp key is special and can take an offset to current Unix time.
34+ """
35+ p = optparse .OptionParser (description = fix_optionparser_whitespace (main .__doc__ ),
36+ prog = __prog__ ,
37+ version = '%s %s' % (__prog__ , __version__ ),
38+ usage = '%prog [options] input' )
39+ p .add_option ('-n' , '--no-verify' , action = 'store_false' , dest = 'verify' , default = True ,
40+ help = 'ignore signature verification on decode' )
41+ p .add_option ('--key' , dest = 'key' , metavar = 'KEY' , default = None ,
42+ help = 'set the secret key to sign with' )
43+ p .add_option ('--alg' , dest = 'algorithm' , metavar = 'ALG' , default = 'HS256' ,
44+ help = 'set crypto algorithm to sign with. default=HS256' )
45+
46+ options , arguments = p .parse_args ()
47+ if len (arguments ) > 0 or not sys .stdin .isatty ():
48+ # Try to decode
49+ try :
50+ if not sys .stdin .isatty ():
51+ token = sys .stdin .read ()
52+ else :
53+ token = arguments [0 ]
54+ valid_jwt = jwt .header (token )
55+ if valid_jwt :
56+ try :
57+ print json .dumps (jwt .decode (token , key = options .key , verify = options .verify ))
58+ sys .exit (0 )
59+ except jwt .DecodeError , e :
60+ print e
61+ sys .exit (0 )
62+ except jwt .DecodeError :
63+ pass
64+
65+ # Try to encode
66+ if options .key is None :
67+ print "Key is required when encoding. See --help for usage."
68+ sys .exit (1 )
69+
70+ # Build payload object to encode
71+ payload = {}
72+ for arg in arguments :
73+ try :
74+ k ,v = arg .split ('=' , 1 )
75+ # exp special case?
76+ if k == 'exp' and v [0 ] == '+' and len (v ) > 1 :
77+ v = str (int (time .time ()+ int (v [1 :])))
78+ # Cast to integer?
79+ if v .isdigit ():
80+ v = int (v )
81+ else :
82+ # Cast to float?
83+ try :
84+ v = float (v )
85+ except ValueError :
86+ pass
87+ # Cast to true, false, or null?
88+ constants = {'true' : True , 'false' : False , 'null' : None }
89+ if v in constants :
90+ v = constants [v ]
91+ payload [k ] = v
92+ except ValueError :
93+ print "Invalid encoding input at %s" % arg
94+ sys .exit (1 )
95+
96+ try :
97+ print jwt .encode (payload , key = options .key , algorithm = options .algorithm )
98+ except Exception , e :
99+ print e
100+ else :
101+ p .print_help ()
102+
103+ if __name__ == '__main__' :
104+ main ()
0 commit comments