def request(self, operation, url, data=None, headers=None): all_headers = self.headers.copy() if headers: all_headers.update(headers) data_str = data if data: if isinstance(data, list): converted_parts = [gdata.alt.appengine._convert_data_part(x) for x in data] data_str = ''.join(converted_parts) else: data_str = gdata.alt.appengine._convert_data_part(data) if data and 'Content-Length' not in all_headers: all_headers['Content-Length'] = str(len(data_str)) if 'Content-Type' not in all_headers: all_headers['Content-Type'] = 'application/atom+xml' if operation is None: method = None elif security.compare_hashes(operation, 'GET'): method = urlfetch.GET elif security.compare_hashes(operation, 'POST'): method = urlfetch.POST elif security.compare_hashes(operation, 'PUT'): method = urlfetch.PUT elif security.compare_hashes(operation, 'DELETE'): method = urlfetch.DELETE else: method = None result = yield ndb.get_context().urlfetch(url=str(url), payload=data_str, method=method, headers=all_headers, follow_redirects=False, deadline=self.deadline) raise ndb.Return(gdata.alt.appengine.HttpResponse(result))
def query(self, query_string, key=None): uri = "?".join((self._endpoint, urllib.urlencode({"key": key or self.key, "tq": query_string}))) result = self.client.GetWithRetries(uri, converter=self._converter, logger=logging.getLogger()) if security.compare_hashes(result["status"], "error"): logging.error(result["errors"]) return cols = tuple([col["label"] or col["id"] for col in result["table"]["cols"]]) for row in result["table"]["rows"]: yield dict(zip(cols, [c["v"] for c in row["c"]]))
def post(self): event = self.request.headers.get('x-github-event', '') signature = self.request.headers.get('x-hub-signature', '') body = self.request.body expected_signature = make_signature(body) if not security.compare_hashes(signature, expected_signature): logging.error('webhook failed signature check') self.abort(400) body_json = json.loads(body) repo = body_json.get('repository', {}).get('full_name') number = None if 'pull_request' in body_json: number = body_json['pull_request']['number'] elif 'issue' in body_json: number = body_json['issue']['number'] parent = None if number: parent = models.GitHubResource.make_key(repo, number) kwargs = {} timestamp = self.request.headers.get('x-timestamp') if timestamp is not None: kwargs['timestamp'] = datetime.datetime.strptime( timestamp, '%Y-%m-%d %H:%M:%S.%f') webhook = models.GitHubWebhookRaw( parent=parent, repo=repo, number=number, event=event, guid=self.request.headers.get('x-github-delivery', ''), body=body, **kwargs ) webhook.put() # Defer digest updates, so they'll retry on failure. if event == 'status': status = models.GHStatus.from_json(body_json) models.save_if_newer(status) query = models.GHIssueDigest.find_head(repo, status.sha) for issue in query.fetch(): deferred.defer(update_issue_digest, issue.repo, issue.number) if number: deferred.defer(update_issue_digest, repo, number)
def post(self): event = self.request.headers.get('x-github-event', '') signature = self.request.headers.get('x-hub-signature', '') body = self.request.body expected_signature = make_signature(body) if not security.compare_hashes(signature, expected_signature): logging.error('webhook failed signature check') self.abort(400) body_json = json.loads(body) repo = body_json.get('repository', {}).get('full_name') number = None if 'pull_request' in body_json: number = body_json['pull_request']['number'] elif 'issue' in body_json: number = body_json['issue']['number'] parent = None if number: parent = models.GithubResource.make_key(repo, number) kwargs = {} timestamp = self.request.headers.get('x-timestamp') if timestamp is not None: kwargs['timestamp'] = datetime.datetime.strptime( timestamp, '%Y-%m-%d %H:%M:%S.%f') webhook = models.GithubWebhookRaw( parent=parent, repo=repo, number=number, event=event, guid=self.request.headers.get('x-github-delivery', ''), body=body, **kwargs ) webhook.put() # Defer digest updates, so they'll retry on failure. if event == 'status': status = models.GHStatus.from_json(body_json) models.save_if_newer(status) query = models.GHIssueDigest.find_head(repo, status.sha) for issue in query.fetch(): deferred.defer(update_issue_digest, issue.repo, issue.number) if number: deferred.defer(update_issue_digest, repo, number)
def inner(self, *argv, **kwargv): ndb.toplevel(func)(self, *argv, **kwargv) if origin is None: allow_origin = self.request.headers.get("Origin") if allow_origin is None and self.request.referer: allow_origin = "{0}://{1}".format(*urlparse(self.request.referer)[:2]) else: if callable(origin): allow_origin = origin() if allow_origin: self.response.headers["Access-Control-Allow-Origin"] = allow_origin if security.compare_hashes(self.request.method, "OPTIONS"): self.response.headers["Access-Control-Max-Age"] = tap.config.CORS_Access_Control_Max_Age method = self.request.headers.get("Access-Control-Request-Method") if method: self.response.headers["Access-Control-Allow-Methods"] = method headers = self.request.headers.get("Access-Control-Request-Headers") if headers: self.response.headers["Access-Control-Allow-Headers"] = headers
def deserialize(self, name, value, max_age=None): """Deserializes a signed cookie value. :param name: Cookie name. :param value: A cookie value to be deserialized. :param max_age: Maximum age in seconds for a valid cookie. If the cookie is older than this, returns None. :returns: The deserialized secure cookie, or None if it is not valid. """ if not value: return None name = webapp2._to_utf8(name) value = webapp2._to_utf8(value) # Unquote for old WebOb. value = http_cookies._unquote(value) parts = value.split(b'|') if len(parts) != 3: return None signature = self._get_signature(name, parts[0], parts[1]) if not security.compare_hashes(parts[2], signature): logging.warning('Invalid cookie signature %r', value) return None if max_age is not None: if int(parts[1]) < self._get_timestamp() - max_age: logging.warning('Expired cookie %r', value) return None try: return self._decode(parts[0]) except Exception: logging.warning('Cookie value failed to be decoded: %r', parts[0]) return None
def inner(self, *argv, **kwargv): if security.compare_hashes(self.request.method, "GET"): token = uuid.uuid4().get_hex() with tap.on_namespace(namespace): ndb.get_context().memcache_set(token, "", time=tap.config.CSRF_TIME) self.context["csrf"] = token elif self.request.method in ("POST", "PUT", "DELETE"): def set_403(): self.response.set_status(403, "Invalid CSRF token") self.response.write("<h1>Invalid CSRF token</h1>\n<p>Please reload the form page</p>\n") token = self.request.POST.get("csrf") if not token: set_403() return with tap.on_namespace(namespace): result = yield ndb.get_context().memcache_delete(token) if result != memcache.DELETE_SUCCESSFUL: set_403() return func(self, *argv, **kwargv)
def delete(self, request): user_key = model.User.gen_key(tap.endpoints.get_user_id()) project_key = ndb.Key(model.Project, request.key) user, project = yield ndb.get_multi_async((user_key, project_key)) if not user: raise endpoints.UnauthorizedException() if not project: raise endpoints.NotFoundException() if not user.key in project.admin: raise endpoints.ForbiddenException() if not project.closed: raise endpoints.BadRequestException() if not security.compare_hashes(request.name, project.name): raise endpoints.BadRequestException() if project.is_public: ProjectSearchIndex.update(project, will_un_public=False) ProjectDelete.run(project.key) raise ndb.Return(message_types.VoidMessage())
def to_blob(headerlist, body): blob = dict(headerlist=[(k,v) for k,v in headerlist if not security.compare_hashes(k, "Content-Length")], body=body) return tap.dumps(blob)
def get(self, arg): # Documentation here: https://developer.github.com/v3/oauth/ client_id, client_secret = self.github_client() if arg.endswith('/done'): target, done = arg[:-len('/done')], True else: target, done = arg, False if not done: # 1) Redirect users to request GitHub access if self.session.get('user'): # User already logged in, no need to continue. self.maybe_redirect(target) return state = security.generate_random_string(entropy=128) args = { 'client_id': client_id, 'redirect_uri': self.request.url + '/done', 'scope': '', # Username only needs "public data" permission! 'state': state } self.session['gh_state'] = state self.redirect('https://github.com/login/oauth/authorize?' + urllib.urlencode(args)) else: # 2) GitHub redirects back to your site code = self.request.get('code') state = self.request.get('state') session_state = self.session.pop('gh_state', '') if not state or not code: self.abort(400) if not security.compare_hashes(state, session_state): # States must match to avoid CSRF. # Full attack details here: # http://homakov.blogspot.com/2012/07/saferweb-most-common-oauth2.html self.abort(400) # 3) Use the access token to access the API params = { 'client_id': client_id, 'client_secret': client_secret, 'code': code, 'state': session_state, } resp = urlfetch.fetch( 'https://github.com/login/oauth/access_token', payload=urllib.urlencode(params), method='POST', headers={'Accept': 'application/json'}) if resp.status_code != 200: logging.error('failed to vend token: status %d', resp.status_code) self.abort(500) vended = json.loads(resp.content) resp = urlfetch.fetch( 'https://api.github.com/user', headers={'Authorization': 'token ' + vended['access_token']}) if resp.status_code != 200: logging.error('failed to get user name: status %d', resp.status_code) self.abort(500) user_info = json.loads(resp.content) login = user_info['login'] logging.info('successful login for %s', login) # Save the GitHub username to the session. # Note: we intentionally discard the access_token here, # since we don't need it for anything more. self.session['user'] = login self.response.write('<h1>Welcome, %s</h1>' % login) self.maybe_redirect(target)
def verify(self, password): hashedPassword = security.hash_password(password, 'sha1', self.passwordSalt, passwordPepper) return security.compare_hashes(hashedPassword, self.hashedPassword)
def get(self, arg): # Documentation here: https://developer.github.com/v3/oauth/ client_id, client_secret = self.github_client() if arg.endswith('/done'): target, done = arg[:-len('/done')], True else: target, done = arg, False if not done: # 1) Redirect users to request GitHub access if self.session.get('user'): # User already logged in, no need to continue. self.maybe_redirect(target) return state = security.generate_random_string(entropy=128) args = { 'client_id': client_id, 'redirect_uri': self.request.url + '/done', 'scope': '', # Username only needs "public data" permission! 'state': state } self.session['gh_state'] = state self.redirect('https://github.com/login/oauth/authorize?' + urllib.urlencode(args)) else: # 2) GitHub redirects back to your site code = self.request.get('code') state = self.request.get('state') session_state = self.session.pop('gh_state', '') if not state or not code: self.abort(400) if not security.compare_hashes(state, session_state): # States must match to avoid CSRF. # Full attack details here: # http://homakov.blogspot.com/2012/07/saferweb-most-common-oauth2.html self.abort(400) # 3) Use the access token to access the API params = { 'client_id': client_id, 'client_secret': client_secret, 'code': code, 'state': session_state, } resp = urlfetch.fetch( 'https://github.com/login/oauth/access_token', payload=urllib.urlencode(params), method='POST', headers={'Accept': 'application/json'} ) if resp.status_code != 200: logging.error('failed to vend token: status %d', resp.status_code) self.abort(500) vended = json.loads(resp.content) resp = urlfetch.fetch( 'https://api.github.com/user', headers={'Authorization': 'token ' + vended['access_token']}) if resp.status_code != 200: logging.error('failed to get user name: status %d', resp.status_code) self.abort(500) user_info = json.loads(resp.content) login = user_info['login'] logging.info('successful login for %s', login) # Save the GitHub username to the session. # Note: we intentionally discard the access_token here, # since we don't need it for anything more. self.session['user'] = login self.response.write('<h1>Welcome, %s</h1>' % login) self.maybe_redirect(target)