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

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

Issue 1858763003: Change origin trial token format (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Nits Created 4 years, 8 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
« no previous file with comments | « third_party/WebKit/LayoutTests/http/tests/origin_trials/sample-api-stolen.html ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2016 The Chromium Authors. All rights reserved. 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 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 """Utility for generating experimental API tokens 6 """Utility for generating experimental API tokens
7 7
8 usage: generate_token.py [-h] [--key-file KEY_FILE] 8 usage: generate_token.py [-h] [--key-file KEY_FILE]
9 [--expire-days EXPIRE_DAYS | 9 [--expire-days EXPIRE_DAYS |
10 --expire-timestamp EXPIRE_TIMESTAMP] 10 --expire-timestamp EXPIRE_TIMESTAMP]
11 origin trial_name 11 origin trial_name
12 12
13 Run "generate_token.py -h" for more help on usage. 13 Run "generate_token.py -h" for more help on usage.
14 """ 14 """
15 import argparse 15 import argparse
16 import base64 16 import base64
17 import json
17 import re 18 import re
18 import os 19 import os
20 import struct
19 import sys 21 import sys
20 import time 22 import time
21 import urlparse 23 import urlparse
22 24
23 script_dir = os.path.dirname(os.path.realpath(__file__)) 25 script_dir = os.path.dirname(os.path.realpath(__file__))
24 sys.path.insert(0, os.path.join(script_dir, 'third_party', 'ed25519')) 26 sys.path.insert(0, os.path.join(script_dir, 'third_party', 'ed25519'))
25 import ed25519 27 import ed25519
26 28
27 29
28 # Matches a valid DNS name label (alphanumeric plus hyphens, except at the ends, 30 # Matches a valid DNS name label (alphanumeric plus hyphens, except at the ends,
29 # no longer than 63 ASCII characters) 31 # no longer than 63 ASCII characters)
30 DNS_LABEL_REGEX = re.compile(r"^(?!-)[a-z\d-]{1,63}(?<!-)$", re.IGNORECASE) 32 DNS_LABEL_REGEX = re.compile(r"^(?!-)[a-z\d-]{1,63}(?<!-)$", re.IGNORECASE)
31 33
34 # This script generates Version 2 tokens.
35 VERSION = "\x02"
36
32 def HostnameFromArg(arg): 37 def HostnameFromArg(arg):
33 """Determines whether a string represents a valid hostname. 38 """Determines whether a string represents a valid hostname.
34 39
35 Returns the canonical hostname if its argument is valid, or None otherwise. 40 Returns the canonical hostname if its argument is valid, or None otherwise.
36 """ 41 """
37 if not arg or len(arg) > 255: 42 if not arg or len(arg) > 255:
38 return None 43 return None
39 if arg[-1] == ".": 44 if arg[-1] == ".":
40 arg = arg[:-1] 45 arg = arg[:-1]
41 if all(DNS_LABEL_REGEX.match(label) for label in arg.split(".")): 46 if all(DNS_LABEL_REGEX.match(label) for label in arg.split(".")):
(...skipping 26 matching lines...) Expand all
68 port = {"https": 443, "http": 80}[origin.scheme] 73 port = {"https": 443, "http": 80}[origin.scheme]
69 # Strip any extra components and return the origin URL: 74 # Strip any extra components and return the origin URL:
70 return "{0}://{1}:{2}".format(origin.scheme, origin.hostname, port) 75 return "{0}://{1}:{2}".format(origin.scheme, origin.hostname, port)
71 76
72 def ExpiryFromArgs(args): 77 def ExpiryFromArgs(args):
73 if args.expire_timestamp: 78 if args.expire_timestamp:
74 return int(args.expire_timestamp) 79 return int(args.expire_timestamp)
75 return (int(time.time()) + (int(args.expire_days) * 86400)) 80 return (int(time.time()) + (int(args.expire_days) * 86400))
76 81
77 def GenerateTokenData(origin, api_name, expiry): 82 def GenerateTokenData(origin, api_name, expiry):
78 return "{0}|{1}|{2}".format(origin, api_name, expiry) 83 return json.dumps({"origin": origin,
84 "feature": api_name,
85 "expiry": expiry}).encode('utf-8')
86
87 def GenerateDataToSign(version, data):
88 return version + struct.pack(">I",len(data)) + data
79 89
80 def Sign(private_key, data): 90 def Sign(private_key, data):
81 return ed25519.signature(data, private_key[:32], private_key[32:]) 91 return ed25519.signature(data, private_key[:32], private_key[32:])
82 92
83 def FormatToken(version, signature, data): 93 def FormatToken(version, signature, data):
84 return version + "|" + base64.b64encode(signature) + "|" + data 94 return base64.b64encode(version + signature +
95 struct.pack(">I",len(data)) + data)
85 96
86 def main(): 97 def main():
87 parser = argparse.ArgumentParser( 98 parser = argparse.ArgumentParser(
88 description="Generate tokens for enabling experimental APIs") 99 description="Generate tokens for enabling experimental APIs")
89 parser.add_argument("origin", 100 parser.add_argument("origin",
90 help="Origin for which to enable the API. This can be " 101 help="Origin for which to enable the API. This can be "
91 "either a hostname (default scheme HTTPS, default " 102 "either a hostname (default scheme HTTPS, default "
92 "port 443) or a URL.", 103 "port 443) or a URL.",
93 type=OriginFromArg) 104 type=OriginFromArg)
94 parser.add_argument("trial_name", 105 parser.add_argument("trial_name",
(...skipping 21 matching lines...) Expand all
116 127
117 # Validate that the key file read was a proper Ed25519 key -- running the 128 # Validate that the key file read was a proper Ed25519 key -- running the
118 # publickey method on the first half of the key should return the second 129 # publickey method on the first half of the key should return the second
119 # half. 130 # half.
120 if (len(private_key) < 64 or 131 if (len(private_key) < 64 or
121 ed25519.publickey(private_key[:32]) != private_key[32:]): 132 ed25519.publickey(private_key[:32]) != private_key[32:]):
122 print("Unable to use the specified private key file.") 133 print("Unable to use the specified private key file.")
123 sys.exit(1) 134 sys.exit(1)
124 135
125 token_data = GenerateTokenData(args.origin, args.trial_name, expiry) 136 token_data = GenerateTokenData(args.origin, args.trial_name, expiry)
126 signature = Sign(private_key, token_data) 137 data_to_sign = GenerateDataToSign(VERSION, token_data)
138 signature = Sign(private_key, data_to_sign)
127 139
128 # Verify that that the signature is correct before printing it. 140 # Verify that that the signature is correct before printing it.
129 try: 141 try:
130 ed25519.checkvalid(signature, token_data, private_key[32:]) 142 ed25519.checkvalid(signature, data_to_sign, private_key[32:])
131 except Exception, exc: 143 except Exception, exc:
132 print "There was an error generating the signature." 144 print "There was an error generating the signature."
133 print "(The original error was: %s)" % exc 145 print "(The original error was: %s)" % exc
134 sys.exit(1) 146 sys.exit(1)
135 147
136 # Output a properly-formatted token. Version 1 is hard-coded, as it is 148 # Output a properly-formatted token. Version 1 is hard-coded, as it is
137 # the only defined token version. 149 # the only defined token version.
138 print FormatToken("1", signature, token_data) 150 print FormatToken(VERSION, signature, token_data)
139 151
140 if __name__ == "__main__": 152 if __name__ == "__main__":
141 main() 153 main()
OLDNEW
« no previous file with comments | « third_party/WebKit/LayoutTests/http/tests/origin_trials/sample-api-stolen.html ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698