Chromium Code Reviews| OLD | NEW |
|---|---|
| 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] |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 79 if not port: | 79 if not port: |
| 80 port = {"https": 443, "http": 80}[origin.scheme] | 80 port = {"https": 443, "http": 80}[origin.scheme] |
| 81 # Strip any extra components and return the origin URL: | 81 # Strip any extra components and return the origin URL: |
| 82 return "{0}://{1}:{2}".format(origin.scheme, origin.hostname, port) | 82 return "{0}://{1}:{2}".format(origin.scheme, origin.hostname, port) |
| 83 | 83 |
| 84 def ExpiryFromArgs(args): | 84 def ExpiryFromArgs(args): |
| 85 if args.expire_timestamp: | 85 if args.expire_timestamp: |
| 86 return int(args.expire_timestamp) | 86 return int(args.expire_timestamp) |
| 87 return (int(time.time()) + (int(args.expire_days) * 86400)) | 87 return (int(time.time()) + (int(args.expire_days) * 86400)) |
| 88 | 88 |
| 89 def ValidateSubdomainTokenOrigin(origin): | |
| 90 """ Calls validate_subdomain_origin utility to check the origin | |
| 91 | |
| 92 If the utility is not found, prints a warning for manual validation, and | |
| 93 returns True | |
| 94 """ | |
| 95 utility_path = "bin/validate_subdomain_origin" | |
|
iclelland
2016/11/02 15:25:47
How does this utility end up in a bin/ directory?
chasej
2016/11/03 19:23:39
I forgot to add instructions, but I just used a sy
| |
| 96 if not os.path.exists(utility_path): | |
| 97 print "WARNING!" | |
| 98 print "Origin not validated for use in subdomain token" | |
| 99 print " (missing '%s' utility)" % utility_path | |
| 100 print "Must manually check origin against the Public Suffix List" | |
| 101 print | |
| 102 return True | |
| 103 | |
| 104 rc = os.system("%s %s >/dev/null 2>&1" % (utility_path, origin)) | |
| 105 return rc == 0 | |
|
iclelland
2016/11/02 15:25:47
It is also possible for other non-zero status to b
chasej
2016/11/03 19:23:39
Done.
| |
| 106 | |
| 89 def GenerateTokenData(origin, is_subdomain, feature_name, expiry): | 107 def GenerateTokenData(origin, is_subdomain, feature_name, expiry): |
| 90 data = {"origin": origin, | 108 data = {"origin": origin, |
| 91 "feature": feature_name, | 109 "feature": feature_name, |
| 92 "expiry": expiry} | 110 "expiry": expiry} |
| 93 if is_subdomain is not None: | 111 if is_subdomain is not None: |
| 94 data["isSubdomain"] = is_subdomain | 112 data["isSubdomain"] = is_subdomain |
| 95 return json.dumps(data).encode('utf-8') | 113 return json.dumps(data).encode('utf-8') |
| 96 | 114 |
| 97 def GenerateDataToSign(version, data): | 115 def GenerateDataToSign(version, data): |
| 98 return version + struct.pack(">I",len(data)) + data | 116 return version + struct.pack(">I",len(data)) + data |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 152 private_key = key_file.read(64) | 170 private_key = key_file.read(64) |
| 153 | 171 |
| 154 # Validate that the key file read was a proper Ed25519 key -- running the | 172 # Validate that the key file read was a proper Ed25519 key -- running the |
| 155 # publickey method on the first half of the key should return the second | 173 # publickey method on the first half of the key should return the second |
| 156 # half. | 174 # half. |
| 157 if (len(private_key) < 64 or | 175 if (len(private_key) < 64 or |
| 158 ed25519.publickey(private_key[:32]) != private_key[32:]): | 176 ed25519.publickey(private_key[:32]) != private_key[32:]): |
| 159 print("Unable to use the specified private key file.") | 177 print("Unable to use the specified private key file.") |
| 160 sys.exit(1) | 178 sys.exit(1) |
| 161 | 179 |
| 180 # For subdomain tokens, validate that the origin is allowed | |
| 181 if args.is_subdomain: | |
| 182 if not ValidateSubdomainTokenOrigin(args.origin): | |
| 183 print "The specified origin is not valid for use in a subdomain token." | |
| 184 sys.exit(1) | |
| 185 | |
| 162 token_data = GenerateTokenData(args.origin, args.is_subdomain, | 186 token_data = GenerateTokenData(args.origin, args.is_subdomain, |
| 163 args.trial_name, expiry) | 187 args.trial_name, expiry) |
| 164 data_to_sign = GenerateDataToSign(VERSION, token_data) | 188 data_to_sign = GenerateDataToSign(VERSION, token_data) |
| 165 signature = Sign(private_key, data_to_sign) | 189 signature = Sign(private_key, data_to_sign) |
| 166 | 190 |
| 167 # Verify that that the signature is correct before printing it. | 191 # Verify that that the signature is correct before printing it. |
| 168 try: | 192 try: |
| 169 ed25519.checkvalid(signature, data_to_sign, private_key[32:]) | 193 ed25519.checkvalid(signature, data_to_sign, private_key[32:]) |
| 170 except Exception, exc: | 194 except Exception, exc: |
| 171 print "There was an error generating the signature." | 195 print "There was an error generating the signature." |
| 172 print "(The original error was: %s)" % exc | 196 print "(The original error was: %s)" % exc |
| 173 sys.exit(1) | 197 sys.exit(1) |
| 174 | 198 |
| 175 | 199 |
| 176 # Output the token details | 200 # Output the token details |
| 177 print "Token details:" | 201 print "Token details:" |
| 178 print " Origin: %s" % args.origin | 202 print " Origin: %s" % args.origin |
| 179 print " Is Subdomain: %s" % args.is_subdomain | 203 print " Is Subdomain: %s" % args.is_subdomain |
| 180 print " Feature: %s" % args.trial_name | 204 print " Feature: %s" % args.trial_name |
| 181 print " Expiry: %d (%s UTC)" % (expiry, datetime.utcfromtimestamp(expiry)) | 205 print " Expiry: %d (%s UTC)" % (expiry, datetime.utcfromtimestamp(expiry)) |
| 182 print | 206 print |
| 183 | 207 |
| 184 # Output the properly-formatted token. | 208 # Output the properly-formatted token. |
| 185 print FormatToken(VERSION, signature, token_data) | 209 print FormatToken(VERSION, signature, token_data) |
| 186 | 210 |
| 187 if __name__ == "__main__": | 211 if __name__ == "__main__": |
| 188 main() | 212 main() |
| OLD | NEW |