#!/usr/bin/env python from __future__ import print_function import optparse import jwt import sys import json import time __prog__ = 'jwt' __version__ = '0.1' def fix_optionparser_whitespace(input): """Hacks around whitespace hypersensitivity in OptionParser""" newline = ' ' * 80 doublespace = '\033[8m.\033[0m' * 2 return input.replace(' ', doublespace).replace('\n', newline) def main(): """Encodes or decodes JSON Web Tokens based on input Decoding examples: %prog --key=secret json.web.token %prog --no-verify json.web.token Encoding requires the key option and takes space separated key/value pairs separated by equals (=) as input. Examples: %prog --key=secret iss=me exp=1302049071 %prog --key=secret foo=bar exp=+10 The exp key is special and can take an offset to current Unix time. """ p = optparse.OptionParser(description=fix_optionparser_whitespace(main.__doc__), prog=__prog__, version='%s %s' % (__prog__, __version__), usage='%prog [options] input') p.add_option('-n', '--no-verify', action='store_false', dest='verify', default=True, help='ignore signature verification on decode') p.add_option('--key', dest='key', metavar='KEY', default=None, help='set the secret key to sign with') p.add_option('--alg', dest='algorithm', metavar='ALG', default='HS256', help='set crypto algorithm to sign with. default=HS256') options, arguments = p.parse_args() if len(arguments) > 0 or not sys.stdin.isatty(): # Try to decode try: if not sys.stdin.isatty(): token = sys.stdin.read() else: token = arguments[0] token = token.encode('utf-8') valid_jwt = jwt.header(token) if valid_jwt: try: print(json.dumps(jwt.decode(token, key=options.key, verify=options.verify))) sys.exit(0) except jwt.DecodeError as e: print(e) sys.exit(1) except jwt.DecodeError: pass # Try to encode if options.key is None: print("Key is required when encoding. See --help for usage.") sys.exit(1) # Build payload object to encode payload = {} for arg in arguments: try: k,v = arg.split('=', 1) # exp +offset special case? if k == 'exp' and v[0] == '+' and len(v) > 1: v = str(int(time.time()+int(v[1:]))) # Cast to integer? if v.isdigit(): v = int(v) else: # Cast to float? try: v = float(v) except ValueError: pass # Cast to true, false, or null? constants = {'true': True, 'false': False, 'null': None} if v in constants: v = constants[v] payload[k] = v except ValueError: print("Invalid encoding input at {}".format(arg)) sys.exit(1) try: print(jwt.encode(payload, key=options.key, algorithm=options.algorithm)) sys.exit(0) except Exception as e: print(e) sys.exit(1) else: p.print_help() if __name__ == '__main__': main()