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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: tools/origin_trials/generate_token.py
diff --git a/tools/origin_trials/generate_token.py b/tools/origin_trials/generate_token.py
new file mode 100755
index 0000000000000000000000000000000000000000..8b1804bda9052aa7e47756b767a6f00b3094310a
--- /dev/null
+++ b/tools/origin_trials/generate_token.py
@@ -0,0 +1,121 @@
+#!/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]
+ origin trial_name
+
+Run "generate_token.py -h" for more help on usage.
+"""
+import argparse
+import base64
+import re
+import os
+import sys
+import time
+import urlparse
+
+from third_party import ed25519
+
+HOSTNAME_REGEX = re.compile(
+ r"""^
+ # Zero or more components, where each one is either a single alphanumeric
+ (([a-z0-9]|
+ # Or multiple alphanumerics with internal hyphens
+ [a-z0-9][a-z0-9-]*[a-z0-9])
+ # Separated by periods
+ \.)*
+ # And followed by a final component.
+ ([a-z0-9]|[a-z0-9][a-z0-9-]*[a-z0-9])$""",
+ re.IGNORECASE | re.VERBOSE
+)
+
+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 HOSTNAME_REGEX.match(arg):
+ 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)
+
+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('origin',
+ help="Origin 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('trial_name',
+ help="Feature to enable. The current list of "
+ "experimental feature trials 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