#!/usr/bin/env python
#
# Copyright 2007 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.
#




"""A handler that exports various App Engine services over HTTP.

You can export this handler in your app by adding it to the builtins section:

builtins:
- remote_api: on

This will add remote_api serving to the path /_ah/remote_api.

You can also add it to your handlers section, e.g.:

  handlers:
  - url: /remote_api(/.*)?
    script: $PYTHON_LIB/google/appengine/ext/remote_api/handler.py

You can use remote_api_stub to remotely access services exported by this
handler. See the documentation in remote_api_stub.py for details on how to do
this.

The handler supports several forms of authentication. By default, it
checks that the user is an admin using the Users API, similar to specifying
"login: admin" in the app.yaml file. It also supports a 'custom header' mode
which can be used in certain scenarios.

To configure the custom header mode, edit an appengine_config file (the same
one you may use to configure appstats) to include a line like this:

  remoteapi_CUSTOM_ENVIRONMENT_AUTHENTICATION = (
      'HTTP_X_APPENGINE_INBOUND_APPID', ['otherappid'] )

See the ConfigDefaults class below for the full set of options available.
"""










import google
import hashlib
import logging
import os
import pickle
import wsgiref.handlers
import yaml

from google.appengine.api import api_base_pb
from google.appengine.api import apiproxy_stub
from google.appengine.api import apiproxy_stub_map
from google.appengine.api import datastore_types
from google.appengine.api import lib_config
from google.appengine.api import oauth
from google.appengine.api import users
from google.appengine.datastore import datastore_pb
from google.appengine.datastore import datastore_rpc
from google.appengine.ext import webapp
from google.appengine.ext.db import metadata
from google.appengine.ext.remote_api import remote_api_pb
from google.appengine.ext.remote_api import remote_api_services
from google.appengine.runtime import apiproxy_errors
from google.appengine.datastore import entity_pb


class ConfigDefaults(object):
  """Configurable constants.

  To override remote_api configuration values, define values like this
  in your appengine_config.py file (in the root of your app):

    remoteapi_CUSTOM_ENVIRONMENT_AUTHENTICATION = (
        'HTTP_X_APPENGINE_INBOUND_APPID', ['otherappid'] )

  You may wish to base this file on sample_appengine_config.py.
  """

  # Allow other App Engine applications to use remote_api with special forms
  # of authentication which appear in the environment. This is a pair,
  # ( environment variable name, [ list of valid values ] ). Some examples:
  # * Allow other applications to use remote_api:
  #   remoteapi_CUSTOM_ENVIRONMENT_AUTHENTICATION = (
  #       'HTTP_X_APPENGINE_INBOUND_APPID', ['otherappid'] )
  # * Allow two specific users (who need not be admins):
  #   remoteapi_CUSTOM_ENVIRONMENT_AUTHENTICATION = ('USER_ID',
  #                                                  [ '1234', '1111' ] )





  # Note that this an alternate to the normal users.is_current_user_admin
  # check--either one may pass.
  CUSTOM_ENVIRONMENT_AUTHENTICATION = ()
  _ALLOW_OAUTH = False


config = lib_config.register('remoteapi', ConfigDefaults.__dict__)


class RemoteDatastoreStub(apiproxy_stub.APIProxyStub):
  """Provides a stub that permits execution of stateful datastore queries.

  Some operations aren't possible using the standard interface. Notably,
  datastore RunQuery operations internally store a cursor that is referenced in
  later Next calls, and cleaned up at the end of each request. Because every
  call to ApiCallHandler takes place in its own request, this isn't possible.

  To work around this, RemoteDatastoreStub provides its own implementation of
  RunQuery that immediately returns the query results.
  """

  def __init__(self, service='datastore_v3', _test_stub_map=None):
    """Constructor.

    Args:
      service: The name of the service
      _test_stub_map: An APIProxyStubMap to use for testing purposes.
    """
    super(RemoteDatastoreStub, self).__init__(service)
    if _test_stub_map:
      self.__call = _test_stub_map.MakeSyncCall
    else:
      self.__call = apiproxy_stub_map.MakeSyncCall

  def _Dynamic_RunQuery(self, request, response):
    """Handle a RunQuery request.

    We handle RunQuery by executing a Query and a Next and returning the result
    of the Next request.

    This method is DEPRECATED, but left in place for older clients.
    """
    runquery_response = datastore_pb.QueryResult()
    self.__call('datastore_v3', 'RunQuery', request, runquery_response)
    if runquery_response.result_size() > 0:

      response.CopyFrom(runquery_response)
      return


    next_request = datastore_pb.NextRequest()
    next_request.mutable_cursor().CopyFrom(runquery_response.cursor())
    next_request.set_count(request.limit())
    self.__call('datastore_v3', 'Next', next_request, response)

  def _Dynamic_TransactionQuery(self, request, response):
    if not request.has_ancestor():
      raise apiproxy_errors.ApplicationError(
          datastore_pb.Error.BAD_REQUEST,
          'No ancestor in transactional query.')

    app_id = datastore_types.ResolveAppId(None)
    if (datastore_rpc._GetDatastoreType(app_id) !=
        datastore_rpc.BaseConnection.HIGH_REPLICATION_DATASTORE):
      raise apiproxy_errors.ApplicationError(
          datastore_pb.Error.BAD_REQUEST,
          'remote_api supports transactional queries only in the '
          'high-replication datastore.')


    entity_group_key = entity_pb.Reference()
    entity_group_key.CopyFrom(request.ancestor())
    group_path = entity_group_key.mutable_path()
    root = entity_pb.Path_Element()
    root.MergeFrom(group_path.element(0))
    group_path.clear_element()
    group_path.add_element().CopyFrom(root)
    eg_element = group_path.add_element()
    eg_element.set_type(metadata.EntityGroup.KIND_NAME)
    eg_element.set_id(metadata.EntityGroup.ID)


    begin_request = datastore_pb.BeginTransactionRequest()
    begin_request.set_app(app_id)
    tx = datastore_pb.Transaction()
    self.__call('datastore_v3', 'BeginTransaction', begin_request, tx)


    request.mutable_transaction().CopyFrom(tx)
    self.__call('datastore_v3', 'RunQuery', request, response.mutable_result())


    get_request = datastore_pb.GetRequest()
    get_request.mutable_transaction().CopyFrom(tx)
    get_request.add_key().CopyFrom(entity_group_key)
    get_response = datastore_pb.GetResponse()
    self.__call('datastore_v3', 'Get', get_request, get_response)
    entity_group = get_response.entity(0)


    response.mutable_entity_group_key().CopyFrom(entity_group_key)
    if entity_group.has_entity():
      response.mutable_entity_group().CopyFrom(entity_group.entity())


    self.__call('datastore_v3', 'Commit', tx, datastore_pb.CommitResponse())

  def _Dynamic_Transaction(self, request, response):
    """Handle a Transaction request.

    We handle transactions by accumulating Put and Delete requests on the client
    end, as well as recording the key and hash of Get requests. When Commit is
    called, Transaction is invoked, which verifies that all the entities in the
    precondition list still exist and their hashes match, then performs a
    transaction of its own to make the updates.
    """

    begin_request = datastore_pb.BeginTransactionRequest()
    begin_request.set_app(os.environ['APPLICATION_ID'])
    begin_request.set_allow_multiple_eg(request.allow_multiple_eg())
    tx = datastore_pb.Transaction()
    self.__call('datastore_v3', 'BeginTransaction', begin_request, tx)


    preconditions = request.precondition_list()
    if preconditions:
      get_request = datastore_pb.GetRequest()
      get_request.mutable_transaction().CopyFrom(tx)
      for precondition in preconditions:
        key = get_request.add_key()
        key.CopyFrom(precondition.key())
      get_response = datastore_pb.GetResponse()
      self.__call('datastore_v3', 'Get', get_request, get_response)
      entities = get_response.entity_list()
      assert len(entities) == request.precondition_size()
      for precondition, entity in zip(preconditions, entities):
        if precondition.has_hash() != entity.has_entity():
          raise apiproxy_errors.ApplicationError(
              datastore_pb.Error.CONCURRENT_TRANSACTION,
              "Transaction precondition failed.")
        elif entity.has_entity():
          entity_hash = hashlib.sha1(entity.entity().Encode()).digest()
          if precondition.hash() != entity_hash:
            raise apiproxy_errors.ApplicationError(
                datastore_pb.Error.CONCURRENT_TRANSACTION,
                "Transaction precondition failed.")


    if request.has_puts():
      put_request = request.puts()
      put_request.mutable_transaction().CopyFrom(tx)
      self.__call('datastore_v3', 'Put', put_request, response)


    if request.has_deletes():
      delete_request = request.deletes()
      delete_request.mutable_transaction().CopyFrom(tx)
      self.__call('datastore_v3', 'Delete', delete_request,
                  datastore_pb.DeleteResponse())


    self.__call('datastore_v3', 'Commit', tx, datastore_pb.CommitResponse())

  def _Dynamic_GetIDsXG(self, request, response):
    self._Dynamic_GetIDs(request, response, is_xg=True)

  def _Dynamic_GetIDs(self, request, response, is_xg=False):
    """Fetch unique IDs for a set of paths."""

    for entity in request.entity_list():
      assert entity.property_size() == 0
      assert entity.raw_property_size() == 0
      assert entity.entity_group().element_size() == 0
      lastpart = entity.key().path().element_list()[-1]
      assert lastpart.id() == 0 and not lastpart.has_name()


    begin_request = datastore_pb.BeginTransactionRequest()
    begin_request.set_app(os.environ['APPLICATION_ID'])
    begin_request.set_allow_multiple_eg(is_xg)
    tx = datastore_pb.Transaction()
    self.__call('datastore_v3', 'BeginTransaction', begin_request, tx)


    self.__call('datastore_v3', 'Put', request, response)


    self.__call('datastore_v3', 'Rollback', tx, api_base_pb.VoidProto())



SERVICE_PB_MAP = remote_api_services.SERVICE_PB_MAP

class ApiCallHandler(webapp.RequestHandler):
  """A webapp handler that accepts API calls over HTTP and executes them."""

  LOCAL_STUBS = {
      'remote_datastore': RemoteDatastoreStub('remote_datastore'),
  }

  OAUTH_SCOPE = 'https://www.googleapis.com/auth/appengine.apis'

  def CheckIsAdmin(self):
    user_is_authorized = False
    if users.is_current_user_admin():
      user_is_authorized = True
    if not user_is_authorized and config.CUSTOM_ENVIRONMENT_AUTHENTICATION:
      if len(config.CUSTOM_ENVIRONMENT_AUTHENTICATION) == 2:
        var, values = config.CUSTOM_ENVIRONMENT_AUTHENTICATION
        if os.getenv(var) in values:
          user_is_authorized = True
      else:
        logging.warning('remoteapi_CUSTOM_ENVIRONMENT_AUTHENTICATION is '
                        'configured incorrectly.')

    if not user_is_authorized and config._ALLOW_OAUTH:
      try:
        user_is_authorized = (
            oauth.is_current_user_admin(_scope=self.OAUTH_SCOPE))
      except oauth.OAuthRequestError:

        pass
    if not user_is_authorized:
      self.response.set_status(401)
      self.response.out.write(
          'You must be logged in as an administrator to access this.')
      self.response.headers['Content-Type'] = 'text/plain'
      return False
    if 'X-appcfg-api-version' not in self.request.headers:
      self.response.set_status(403)
      self.response.out.write('This request did not contain a necessary header')
      self.response.headers['Content-Type'] = 'text/plain'
      return False
    return True

  def CheckConfigIsValid(self):

    if config.CUSTOM_ENVIRONMENT_AUTHENTICATION and config._ALLOW_OAUTH:
      self.response.set_status(400)
      self.response.out.write('You cannot enable both OAuth authentication '
                              '(remoteapi__ALLOW_OAUTH) and '
                              'custom authentication '
                              '(remoteapi_CUSTOM_ENVIRONMENT_AUTHENTICATION).')
      return False
    return True


  def get(self):
    """Handle a GET. Just show an info page."""
    if not self.CheckConfigIsValid() or not self.CheckIsAdmin():
      return

    rtok = self.request.get('rtok', '0')
    app_info = {
        'app_id': os.environ['APPLICATION_ID'],
        'rtok': rtok
        }

    self.response.headers['Content-Type'] = 'text/plain'
    self.response.out.write(yaml.dump(app_info))

  def post(self):
    """Handle POST requests by executing the API call."""
    if not self.CheckConfigIsValid() or not self.CheckIsAdmin():
      return
















    self.response.headers['Content-Type'] = 'text/plain'

    response = remote_api_pb.Response()
    try:
      request = remote_api_pb.Request()



      request.ParseFromString(self.request.body)
      response_data = self.ExecuteRequest(request)
      response.set_response(response_data.Encode())
      self.response.set_status(200)
    except Exception, e:
      logging.exception('Exception while handling %s', request)
      self.response.set_status(200)



      response.set_exception(pickle.dumps(e))
      if isinstance(e, apiproxy_errors.ApplicationError):
        application_error = response.mutable_application_error()
        application_error.set_code(e.application_error)
        application_error.set_detail(e.error_detail)
    self.response.out.write(response.Encode())

  def ExecuteRequest(self, request):
    """Executes an API invocation and returns the response object."""
    service = request.service_name()
    method = request.method()
    service_methods = SERVICE_PB_MAP.get(service, {})
    request_class, response_class = service_methods.get(method, (None, None))
    if not request_class:
      raise apiproxy_errors.CallNotFoundError()

    request_data = request_class()
    request_data.ParseFromString(request.request())
    response_data = response_class()

    if service in self.LOCAL_STUBS:
      self.LOCAL_STUBS[service].MakeSyncCall(service, method, request_data,
                                             response_data)
    else:
      apiproxy_stub_map.MakeSyncCall(service, method, request_data,
                                     response_data)

    return response_data

  def InfoPage(self):
    """Renders an information page."""
    return """
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html><head>
<title>App Engine API endpoint.</title>
</head><body>
<h1>App Engine API endpoint.</h1>
<p>This is an endpoint for the App Engine remote API interface.
Point your stubs (google.appengine.ext.remote_api.remote_api_stub) here.</p>
</body>
</html>"""

application = webapp.WSGIApplication([('.*', ApiCallHandler)])


def main():
  wsgiref.handlers.CGIHandler().run(application)


if __name__ == '__main__':
  main()
