| Index: third_party/oauth2client/devshell.py
 | 
| diff --git a/third_party/oauth2client/devshell.py b/third_party/oauth2client/devshell.py
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..69d3808a3cba1b4e27fd09d14491e2cb6c50d5e8
 | 
| --- /dev/null
 | 
| +++ b/third_party/oauth2client/devshell.py
 | 
| @@ -0,0 +1,135 @@
 | 
| +# Copyright 2015 Google Inc. All Rights Reserved.
 | 
| +#
 | 
| +# 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.
 | 
| +
 | 
| +"""OAuth 2.0 utitilies for Google Developer Shell environment."""
 | 
| +
 | 
| +import json
 | 
| +import os
 | 
| +
 | 
| +from . import client
 | 
| +
 | 
| +
 | 
| +DEVSHELL_ENV = 'DEVSHELL_CLIENT_PORT'
 | 
| +
 | 
| +
 | 
| +class Error(Exception):
 | 
| +  """Errors for this module."""
 | 
| +  pass
 | 
| +
 | 
| +
 | 
| +class CommunicationError(Error):
 | 
| +  """Errors for communication with the Developer Shell server."""
 | 
| +
 | 
| +
 | 
| +class NoDevshellServer(Error):
 | 
| +  """Error when no Developer Shell server can be contacted."""
 | 
| +
 | 
| +
 | 
| +# The request for credential information to the Developer Shell client socket is
 | 
| +# always an empty PBLite-formatted JSON object, so just define it as a constant.
 | 
| +CREDENTIAL_INFO_REQUEST_JSON = '[]'
 | 
| +
 | 
| +
 | 
| +class CredentialInfoResponse(object):
 | 
| +  """Credential information response from Developer Shell server.
 | 
| +
 | 
| +  The credential information response from Developer Shell socket is a
 | 
| +  PBLite-formatted JSON array with fields encoded by their index in the array:
 | 
| +  * Index 0 - user email
 | 
| +  * Index 1 - default project ID. None if the project context is not known.
 | 
| +  * Index 2 - OAuth2 access token. None if there is no valid auth context.
 | 
| +  """
 | 
| +
 | 
| +  def __init__(self, json_string):
 | 
| +    """Initialize the response data from JSON PBLite array."""
 | 
| +    pbl = json.loads(json_string)
 | 
| +    if not isinstance(pbl, list):
 | 
| +      raise ValueError('Not a list: ' + str(pbl))
 | 
| +    pbl_len = len(pbl)
 | 
| +    self.user_email = pbl[0] if pbl_len > 0 else None
 | 
| +    self.project_id = pbl[1] if pbl_len > 1 else None
 | 
| +    self.access_token = pbl[2] if pbl_len > 2 else None
 | 
| +
 | 
| +
 | 
| +def _SendRecv():
 | 
| +  """Communicate with the Developer Shell server socket."""
 | 
| +
 | 
| +  port = int(os.getenv(DEVSHELL_ENV, 0))
 | 
| +  if port == 0:
 | 
| +    raise NoDevshellServer()
 | 
| +
 | 
| +  import socket
 | 
| +
 | 
| +  sock = socket.socket()
 | 
| +  sock.connect(('localhost', port))
 | 
| +
 | 
| +  data = CREDENTIAL_INFO_REQUEST_JSON
 | 
| +  msg = '%s\n%s' % (len(data), data)
 | 
| +  sock.sendall(msg.encode())
 | 
| +
 | 
| +  header = sock.recv(6).decode()
 | 
| +  if '\n' not in header:
 | 
| +    raise CommunicationError('saw no newline in the first 6 bytes')
 | 
| +  len_str, json_str = header.split('\n', 1)
 | 
| +  to_read = int(len_str) - len(json_str)
 | 
| +  if to_read > 0:
 | 
| +    json_str += sock.recv(to_read, socket.MSG_WAITALL).decode()
 | 
| +
 | 
| +  return CredentialInfoResponse(json_str)
 | 
| +
 | 
| +
 | 
| +class DevshellCredentials(client.GoogleCredentials):
 | 
| +  """Credentials object for Google Developer Shell environment.
 | 
| +
 | 
| +  This object will allow a Google Developer Shell session to identify its user
 | 
| +  to Google and other OAuth 2.0 servers that can verify assertions. It can be
 | 
| +  used for the purpose of accessing data stored under the user account.
 | 
| +
 | 
| +  This credential does not require a flow to instantiate because it represents
 | 
| +  a two legged flow, and therefore has all of the required information to
 | 
| +  generate and refresh its own access tokens.
 | 
| +  """
 | 
| +
 | 
| +  def __init__(self, user_agent=None):
 | 
| +    super(DevshellCredentials, self).__init__(
 | 
| +        None,  # access_token, initialized below
 | 
| +        None,  # client_id
 | 
| +        None,  # client_secret
 | 
| +        None,  # refresh_token
 | 
| +        None,  # token_expiry
 | 
| +        None,  # token_uri
 | 
| +        user_agent)
 | 
| +    self._refresh(None)
 | 
| +
 | 
| +  def _refresh(self, http_request):
 | 
| +    self.devshell_response = _SendRecv()
 | 
| +    self.access_token = self.devshell_response.access_token
 | 
| +
 | 
| +  @property
 | 
| +  def user_email(self):
 | 
| +    return self.devshell_response.user_email
 | 
| +
 | 
| +  @property
 | 
| +  def project_id(self):
 | 
| +    return self.devshell_response.project_id
 | 
| +
 | 
| +  @classmethod
 | 
| +  def from_json(cls, json_data):
 | 
| +    raise NotImplementedError(
 | 
| +        'Cannot load Developer Shell credentials from JSON.')
 | 
| +
 | 
| +  @property
 | 
| +  def serialization_data(self):
 | 
| +    raise NotImplementedError(
 | 
| +        'Cannot serialize Developer Shell credentials.')
 | 
| 
 |