Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: tools/experiments/generate_token.py

Issue 1578793002: Add experimental framework token generation tool (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressing review comments Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
chasej 2016/01/22 18:14:00 Should we use something other than "hostname" for
chasej 2016/01/22 18:14:00 I would suggest "trial_name" to replace "api_name"
iclelland 2016/01/22 20:31:57 Done.
iclelland 2016/01/22 20:31:57 Done.
12
13 Run "generate_token.py -h" for more help on usage.
14 """
15 import argparse
16 import base64
17 import re
18 import os
19 import sys
20 import time
21 import urlparse
22
23 from third_party import ed25519
24
25 HOSTNAME_REGEX = re.compile(
26 r"""^
27 # Zero or more components, where each one is either a single alphanumeric
28 (([a-z0-9]|
29 # Or multiple alphanumerics with internal hyphens
30 [a-z0-9][a-z0-9-]*[a-z0-9])
31 # Separated by periods
32 \.)*
33 # And followed by a final component.
34 ([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])$""",
35 re.IGNORECASE | re.VERBOSE
36 )
37
38 def OriginFromArgs(arg):
39 """Constructs the origin for the token from the command line arguments.
40
41 Returns None if this is not possible (neither a valid hostname nor a
42 valid origin URL was provided.)
43 """
44 # Does it look like a hostname?
45 if HOSTNAME_REGEX.match(arg):
46 return 'https://'+arg
47 # Try to construct an origin URL from the argument
48 origin = urlparse.urlparse(arg)
49 if not origin or not origin.scheme or not origin.netloc:
50 raise argparse.ArgumentTypeError("%s is not a hostname or a URL" % arg)
51 # Strip any other components and return the URL:
52 return urlparse.urlunparse(origin[:2] + ('', )*4)
53
54 def ExpiryFromArgs(args):
55 if args.expire_timestamp:
56 return int(args.expire_timestamp)
57 return ((int(time.time()) + (int(args.expire_days) * 86400)) * 1000)
58
59 def GenerateTokenData(origin, apiName, expiry):
60 return "{0}|{1}|{2}".format(origin, apiName, expiry)
61
62 def Sign(private_key, data):
63 return ed25519.signature(data, private_key[:32], private_key[32:])
64
65 def FormatToken(signature, data):
66 return base64.b64encode(signature) + "|" + data
67
68 def main():
69 parser = argparse.ArgumentParser(
70 description="Generate tokens for enabling experimental APIs")
71 parser.add_argument('hostname',
72 help="Host for which to enable the API. This can be a "
73 "bare hostname (in which case https will be "
74 "assumed,) or a valid origin URL (hostname, "
75 "protocol and port can all be included.)",
76 type=OriginFromArgs)
77 parser.add_argument('api_name',
78 help="API to enable. The current list of experimental "
79 "APIs can be found in RuntimeFeatures.in")
80 parser.add_argument('--key-file',
81 help='Ed25519 private key file to sign the token with',
82 default="eftest.key")
83 expiry_group = parser.add_mutually_exclusive_group()
84 expiry_group.add_argument('--expire-days',
85 help='Days from now when the token should exipire',
86 type=int,
87 default=42)
88 expiry_group.add_argument('--expire-timestamp',
89 help="Exact time (milliseconds since 1970-01-01 "
90 "00:00:00 UTC) when the token should exipire",
91 type=int)
92
93 args = parser.parse_args()
94 expiry = ExpiryFromArgs(args)
95
96 key_file = open(os.path.expanduser(args.key_file))
97 private_key = key_file.read()
98
99 # Validate that the key file read was a proper Ed25519 key -- running the
100 # publickey method on the first half of the key should return the second
101 # half.
102 if (len(private_key) != 64 or
103 ed25519.publickey(private_key[:32]) != private_key[32:]):
104 print("Unable to use the specified private key file.")
105 sys.exit(1)
106
107 token_data = GenerateTokenData(args.hostname, args.api_name, expiry)
108 signature = Sign(private_key, token_data)
109
110 # Verify that that the signature is correct before printing it.
111 try:
112 ed25519.checkvalid(signature, token_data, private_key[32:])
113 except Exception:
114 print "There was an error generating the signature."
115 sys.exit(1)
116
117 print FormatToken(signature, token_data)
118
119 if __name__ == "__main__":
120 main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698