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

Unified 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: Add OWNERS file for tool directory 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 side-by-side diff with in-line comments
Download patch
Index: tools/experiments/generate_token.py
diff --git a/tools/experiments/generate_token.py b/tools/experiments/generate_token.py
new file mode 100755
index 0000000000000000000000000000000000000000..79bfb61cfba136155c1f8194420695f84cc0ef88
--- /dev/null
+++ b/tools/experiments/generate_token.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python
+# Copyright (c) 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Utility for generating experimental API tokens
+
+usage: generate_token.py [-h] [--key-file KEY_FILE]
+ [--expire-days EXPIRE_DAYS |
+ --expire-timestamp EXPIRE_TIMESTAMP]
+ hostname api_name
+
+Generate tokens for enabling experimental APIs
+
+positional arguments:
+ hostname Host for which to enable the API. This can be a bare
+ hostname (in which case https will be assumed,) or a
+ valid origin URL (hostname, protocol and port can all
+ be included.)
+ api_name API to enable. The current list of experimental APIs
+ can be found in RuntimeFeatures.in
+
+optional arguments:
+ -h, --help show this help message and exit
+ --key-file KEY_FILE Ed25519 private key file to sign the token with
+ --expire-days EXPIRE_DAYS
+ Days from now when the token should exipire
+ --expire-timestamp EXPIRE_TIMESTAMP
+ Exact time (milliseconds since 1970-01-01 00:00:00
+ 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
+"""
+import argparse
+import base64
+import re
+import os
+import sys
+import time
+import urlparse
+
+from third_party import ed25519
+
+def OriginFromArgs(arg):
+ """Constructs the origin for the token from the command line arguments.
+
+ Returns None if this is not possible (neither a valid hostname nor a
+ valid origin URL was provided.)
+ """
+ # Does it look like a hostname?
+ 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
+ return 'https://'+arg
+ # Try to construct an origin URL from the argument
+ origin = urlparse.urlparse(arg)
+ if not origin or not origin.scheme or not origin.netloc:
+ raise argparse.ArgumentTypeError("%s is not a hostname or a URL" % arg)
+ # Strip any other components and return the URL:
+ 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.
+
+def ExpiryFromArgs(args):
+ if args.expire_timestamp:
+ return int(args.expire_timestamp)
+ return ((int(time.time()) + (int(args.expire_days) * 86400)) * 1000)
+
+def GenerateTokenData(origin, apiName, expiry):
+ return "{0}|{1}|{2}".format(origin, apiName, expiry)
+
+def Sign(private_key, data):
+ return ed25519.signature(data, private_key[:32], private_key[32:])
+
+def FormatToken(signature, data):
+ return base64.b64encode(signature) + "|" + data
+
+def main():
+ parser = argparse.ArgumentParser(
+ description="Generate tokens for enabling experimental APIs")
+ parser.add_argument('hostname',
+ help="Host for which to enable the API. This can be a "
+ "bare hostname (in which case https will be "
+ "assumed,) or a valid origin URL (hostname, "
+ "protocol and port can all be included.)",
+ type=OriginFromArgs)
+ parser.add_argument('api_name',
+ help="API to enable. The current list of experimental "
+ "APIs can be found in RuntimeFeatures.in")
+ parser.add_argument('--key-file',
+ help='Ed25519 private key file to sign the token with',
+ default="eftest.key")
+ expiry_group = parser.add_mutually_exclusive_group()
+ expiry_group.add_argument('--expire-days',
+ help='Days from now when the token should exipire',
+ type=int,
+ default=42)
+ expiry_group.add_argument('--expire-timestamp',
+ help="Exact time (milliseconds since 1970-01-01 "
+ "00:00:00 UTC) when the token should exipire",
+ type=int)
+
+ args = parser.parse_args()
+ expiry = ExpiryFromArgs(args)
+
+ key_file = open(os.path.expanduser(args.key_file))
+ private_key = key_file.read()
+
+ # Validate that the key file read was a proper Ed25519 key -- running the
+ # publickey method on the first half of the key should return the second
+ # half.
+ if (len(private_key) != 64 or
+ ed25519.publickey(private_key[:32]) != private_key[32:]):
+ print("Unable to use the specified private key file.")
+ sys.exit(1)
+
+ token_data = GenerateTokenData(args.hostname, args.api_name, expiry)
+ signature = Sign(private_key, token_data)
+
+ # Verify that that the signature is correct before printing it.
+ try:
+ ed25519.checkvalid(signature, token_data, private_key[32:])
+ except Exception:
+ print "There was an error generating the signature."
+ sys.exit(1)
+
+ print FormatToken(signature, token_data)
+
+if __name__ == "__main__":
+ main()

Powered by Google App Engine
This is Rietveld 408576698