Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 #!/usr/bin/env python | |
| 2 # Copyright (c) 2016 The Chromium Authors. All rights reserved. | |
| 3 # Use of this source code is governed by a BSD-style license that can be | |
| 4 # found in the LICENSE file. | |
| 5 | |
| 6 """Utility for generating experimental API tokens | |
| 7 | |
| 8 usage: generate_token.py [-h] [--key-file KEY_FILE] | |
| 9 [--expire-days EXPIRE_DAYS | | |
| 10 --expire-timestamp EXPIRE_TIMESTAMP] | |
| 11 hostname api_name | |
| 12 | |
| 13 Generate tokens for enabling experimental APIs | |
| 14 | |
| 15 positional arguments: | |
| 16 hostname Host for which to enable the API. This can be a bare | |
| 17 hostname (in which case https will be assumed,) or a | |
| 18 valid origin URL (hostname, protocol and port can all | |
| 19 be included.) | |
| 20 api_name API to enable. The current list of experimental APIs | |
| 21 can be found in RuntimeFeatures.in | |
| 22 | |
| 23 optional arguments: | |
| 24 -h, --help show this help message and exit | |
| 25 --key-file KEY_FILE Ed25519 private key file to sign the token with | |
| 26 --expire-days EXPIRE_DAYS | |
| 27 Days from now when the token should exipire | |
| 28 --expire-timestamp EXPIRE_TIMESTAMP | |
| 29 Exact time (milliseconds since 1970-01-01 00:00:00 | |
| 30 UTC) when the token should exipire | |
|
miket_OOO
2016/01/21 21:54:56
This is up to you, but if this is just a rote copy
iclelland
2016/01/22 20:31:57
It is a rote copy, just for anyone reading the cod
| |
| 31 """ | |
| 32 import argparse | |
| 33 import base64 | |
| 34 import re | |
| 35 import os | |
| 36 import sys | |
| 37 import time | |
| 38 import urlparse | |
| 39 | |
| 40 from third_party import ed25519 | |
| 41 | |
| 42 def OriginFromArgs(arg): | |
| 43 """Constructs the origin for the token from the command line arguments. | |
| 44 | |
| 45 Returns None if this is not possible (neither a valid hostname nor a | |
| 46 valid origin URL was provided.) | |
| 47 """ | |
| 48 # Does it look like a hostname? | |
| 49 if re.match('^[a-z0-9.-]*$', arg): | |
|
miket_OOO
2016/01/21 21:54:56
Make sure we (this tool and dev-console server cod
iclelland
2016/01/22 20:31:57
It looks like your regex disallows a '-' as a comp
| |
| 50 return 'https://'+arg | |
| 51 # Try to construct an origin URL from the argument | |
| 52 origin = urlparse.urlparse(arg) | |
| 53 if not origin or not origin.scheme or not origin.netloc: | |
| 54 raise argparse.ArgumentTypeError("%s is not a hostname or a URL" % arg) | |
| 55 # Strip any other components and return the URL: | |
| 56 return urlparse.urlunparse(origin[:2]+('',)*4) | |
|
miket_OOO
2016/01/21 21:54:56
whitespace after comma and around binary operator
iclelland
2016/01/22 20:31:57
Done.
| |
| 57 | |
| 58 def ExpiryFromArgs(args): | |
| 59 if args.expire_timestamp: | |
| 60 return int(args.expire_timestamp) | |
| 61 return ((int(time.time()) + (int(args.expire_days) * 86400)) * 1000) | |
| 62 | |
| 63 def GenerateTokenData(origin, apiName, expiry): | |
| 64 return "{0}|{1}|{2}".format(origin, apiName, expiry) | |
| 65 | |
| 66 def Sign(private_key, data): | |
| 67 return ed25519.signature(data, private_key[:32], private_key[32:]) | |
| 68 | |
| 69 def FormatToken(signature, data): | |
| 70 return base64.b64encode(signature) + "|" + data | |
| 71 | |
| 72 def main(): | |
| 73 parser = argparse.ArgumentParser( | |
| 74 description="Generate tokens for enabling experimental APIs") | |
| 75 parser.add_argument('hostname', | |
| 76 help="Host for which to enable the API. This can be a " | |
| 77 "bare hostname (in which case https will be " | |
| 78 "assumed,) or a valid origin URL (hostname, " | |
| 79 "protocol and port can all be included.)", | |
| 80 type=OriginFromArgs) | |
| 81 parser.add_argument('api_name', | |
| 82 help="API to enable. The current list of experimental " | |
| 83 "APIs can be found in RuntimeFeatures.in") | |
| 84 parser.add_argument('--key-file', | |
| 85 help='Ed25519 private key file to sign the token with', | |
| 86 default="eftest.key") | |
| 87 expiry_group = parser.add_mutually_exclusive_group() | |
| 88 expiry_group.add_argument('--expire-days', | |
| 89 help='Days from now when the token should exipire', | |
| 90 type=int, | |
| 91 default=42) | |
| 92 expiry_group.add_argument('--expire-timestamp', | |
| 93 help="Exact time (milliseconds since 1970-01-01 " | |
| 94 "00:00:00 UTC) when the token should exipire", | |
| 95 type=int) | |
| 96 | |
| 97 args = parser.parse_args() | |
| 98 expiry = ExpiryFromArgs(args) | |
| 99 | |
| 100 key_file = open(os.path.expanduser(args.key_file)) | |
| 101 private_key = key_file.read() | |
| 102 | |
| 103 # Validate that the key file read was a proper Ed25519 key -- running the | |
| 104 # publickey method on the first half of the key should return the second | |
| 105 # half. | |
| 106 if (len(private_key) != 64 or | |
| 107 ed25519.publickey(private_key[:32]) != private_key[32:]): | |
| 108 print("Unable to use the specified private key file.") | |
| 109 sys.exit(1) | |
| 110 | |
| 111 token_data = GenerateTokenData(args.hostname, args.api_name, expiry) | |
| 112 signature = Sign(private_key, token_data) | |
| 113 | |
| 114 # Verify that that the signature is correct before printing it. | |
| 115 try: | |
| 116 ed25519.checkvalid(signature, token_data, private_key[32:]) | |
| 117 except Exception: | |
| 118 print "There was an error generating the signature." | |
| 119 sys.exit(1) | |
| 120 | |
| 121 print FormatToken(signature, token_data) | |
| 122 | |
| 123 if __name__ == "__main__": | |
| 124 main() | |
| OLD | NEW |