Index: client/third_party/google/auth/_helpers.py |
diff --git a/client/third_party/google/auth/_helpers.py b/client/third_party/google/auth/_helpers.py |
new file mode 100644 |
index 0000000000000000000000000000000000000000..860b82719a2a6c5208ca1e410253fe2731818845 |
--- /dev/null |
+++ b/client/third_party/google/auth/_helpers.py |
@@ -0,0 +1,217 @@ |
+# Copyright 2015 Google Inc. |
+# |
+# Licensed under the Apache License, Version 2.0 (the "License"); |
+# you may not use this file except in compliance with the License. |
+# You may obtain a copy of the License at |
+# |
+# http://www.apache.org/licenses/LICENSE-2.0 |
+# |
+# Unless required by applicable law or agreed to in writing, software |
+# distributed under the License is distributed on an "AS IS" BASIS, |
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
+# See the License for the specific language governing permissions and |
+# limitations under the License. |
+ |
+"""Helper functions for commonly used utilities.""" |
+ |
+import base64 |
+import calendar |
+import datetime |
+ |
+import six |
+from six.moves import urllib |
+ |
+ |
+CLOCK_SKEW_SECS = 300 # 5 minutes in seconds |
+CLOCK_SKEW = datetime.timedelta(seconds=CLOCK_SKEW_SECS) |
+ |
+ |
+def copy_docstring(source_class): |
+ """Decorator that copies a method's docstring from another class. |
+ |
+ Args: |
+ source_class (type): The class that has the documented method. |
+ |
+ Returns: |
+ Callable: A decorator that will copy the docstring of the same |
+ named method in the source class to the decorated method. |
+ """ |
+ def decorator(method): |
+ """Decorator implementation. |
+ |
+ Args: |
+ method (Callable): The method to copy the docstring to. |
+ |
+ Returns: |
+ Callable: the same method passed in with an updated docstring. |
+ |
+ Raises: |
+ ValueError: if the method already has a docstring. |
+ """ |
+ if method.__doc__: |
+ raise ValueError('Method already has a docstring.') |
+ |
+ source_method = getattr(source_class, method.__name__) |
+ method.__doc__ = source_method.__doc__ |
+ |
+ return method |
+ return decorator |
+ |
+ |
+def utcnow(): |
+ """Returns the current UTC datetime. |
+ |
+ Returns: |
+ datetime: The current time in UTC. |
+ """ |
+ return datetime.datetime.utcnow() |
+ |
+ |
+def datetime_to_secs(value): |
+ """Convert a datetime object to the number of seconds since the UNIX epoch. |
+ |
+ Args: |
+ value (datetime): The datetime to convert. |
+ |
+ Returns: |
+ int: The number of seconds since the UNIX epoch. |
+ """ |
+ return calendar.timegm(value.utctimetuple()) |
+ |
+ |
+def to_bytes(value, encoding='utf-8'): |
+ """Converts a string value to bytes, if necessary. |
+ |
+ Unfortunately, ``six.b`` is insufficient for this task since in |
+ Python 2 because it does not modify ``unicode`` objects. |
+ |
+ Args: |
+ value (Union[str, bytes]): The value to be converted. |
+ encoding (str): The encoding to use to convert unicode to bytes. |
+ Defaults to "utf-8". |
+ |
+ Returns: |
+ bytes: The original value converted to bytes (if unicode) or as |
+ passed in if it started out as bytes. |
+ |
+ Raises: |
+ ValueError: If the value could not be converted to bytes. |
+ """ |
+ result = (value.encode(encoding) |
+ if isinstance(value, six.text_type) else value) |
+ if isinstance(result, six.binary_type): |
+ return result |
+ else: |
+ raise ValueError('{0!r} could not be converted to bytes'.format(value)) |
+ |
+ |
+def from_bytes(value): |
+ """Converts bytes to a string value, if necessary. |
+ |
+ Args: |
+ value (Union[str, bytes]): The value to be converted. |
+ |
+ Returns: |
+ str: The original value converted to unicode (if bytes) or as passed in |
+ if it started out as unicode. |
+ |
+ Raises: |
+ ValueError: If the value could not be converted to unicode. |
+ """ |
+ result = (value.decode('utf-8') |
+ if isinstance(value, six.binary_type) else value) |
+ if isinstance(result, six.text_type): |
+ return result |
+ else: |
+ raise ValueError( |
+ '{0!r} could not be converted to unicode'.format(value)) |
+ |
+ |
+def update_query(url, params, remove=None): |
+ """Updates a URL's query parameters. |
+ |
+ Replaces any current values if they are already present in the URL. |
+ |
+ Args: |
+ url (str): The URL to update. |
+ params (Mapping[str, str]): A mapping of query parameter |
+ keys to values. |
+ remove (Sequence[str]): Parameters to remove from the query string. |
+ |
+ Returns: |
+ str: The URL with updated query parameters. |
+ |
+ Examples: |
+ |
+ >>> url = 'http://example.com?a=1' |
+ >>> update_query(url, {'a': '2'}) |
+ http://example.com?a=2 |
+ >>> update_query(url, {'b': '3'}) |
+ http://example.com?a=1&b=3 |
+ >> update_query(url, {'b': '3'}, remove=['a']) |
+ http://example.com?b=3 |
+ |
+ """ |
+ if remove is None: |
+ remove = [] |
+ |
+ # Split the URL into parts. |
+ parts = urllib.parse.urlparse(url) |
+ # Parse the query string. |
+ query_params = urllib.parse.parse_qs(parts.query) |
+ # Update the query parameters with the new parameters. |
+ query_params.update(params) |
+ # Remove any values specified in remove. |
+ query_params = { |
+ key: value for key, value |
+ in six.iteritems(query_params) |
+ if key not in remove} |
+ # Re-encoded the query string. |
+ new_query = urllib.parse.urlencode(query_params, doseq=True) |
+ # Unsplit the url. |
+ new_parts = parts._replace(query=new_query) |
+ return urllib.parse.urlunparse(new_parts) |
+ |
+ |
+def scopes_to_string(scopes): |
+ """Converts scope value to a string suitable for sending to OAuth 2.0 |
+ authorization servers. |
+ |
+ Args: |
+ scopes (Sequence[str]): The sequence of scopes to convert. |
+ |
+ Returns: |
+ str: The scopes formatted as a single string. |
+ """ |
+ return ' '.join(scopes) |
+ |
+ |
+def string_to_scopes(scopes): |
+ """Converts stringifed scopes value to a list. |
+ |
+ Args: |
+ scopes (Union[Sequence, str]): The string of space-separated scopes |
+ to convert. |
+ Returns: |
+ Sequence(str): The separated scopes. |
+ """ |
+ if not scopes: |
+ return [] |
+ |
+ return scopes.split(' ') |
+ |
+ |
+def padded_urlsafe_b64decode(value): |
+ """Decodes base64 strings lacking padding characters. |
+ |
+ Google infrastructure tends to omit the base64 padding characters. |
+ |
+ Args: |
+ value (Union[str, bytes]): The encoded value. |
+ |
+ Returns: |
+ bytes: The decoded value |
+ """ |
+ b64string = to_bytes(value) |
+ padded = b64string + b'=' * (-len(b64string) % 4) |
+ return base64.urlsafe_b64decode(padded) |