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

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

Issue 1578793002: Add experimental framework token generation tool (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rename all the things! 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 origin trial_name
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('origin',
72 help="Origin 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('trial_name',
78 help="Feature to enable. The current list of "
79 "experimental feature trials can be found in "
80 "RuntimeFeatures.in")
81 parser.add_argument('--key-file',
82 help='Ed25519 private key file to sign the token with',
83 default="eftest.key")
84 expiry_group = parser.add_mutually_exclusive_group()
85 expiry_group.add_argument('--expire-days',
86 help='Days from now when the token should exipire',
87 type=int,
88 default=42)
89 expiry_group.add_argument('--expire-timestamp',
90 help="Exact time (milliseconds since 1970-01-01 "
91 "00:00:00 UTC) when the token should exipire",
92 type=int)
93
94 args = parser.parse_args()
95 expiry = ExpiryFromArgs(args)
96
97 key_file = open(os.path.expanduser(args.key_file))
98 private_key = key_file.read()
99
100 # Validate that the key file read was a proper Ed25519 key -- running the
101 # publickey method on the first half of the key should return the second
102 # half.
103 if (len(private_key) != 64 or
104 ed25519.publickey(private_key[:32]) != private_key[32:]):
105 print("Unable to use the specified private key file.")
106 sys.exit(1)
107
108 token_data = GenerateTokenData(args.hostname, args.api_name, expiry)
109 signature = Sign(private_key, token_data)
110
111 # Verify that that the signature is correct before printing it.
112 try:
113 ed25519.checkvalid(signature, token_data, private_key[32:])
114 except Exception:
115 print "There was an error generating the signature."
116 sys.exit(1)
117
118 print FormatToken(signature, token_data)
119
120 if __name__ == "__main__":
121 main()
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698