{"action":"created","comment":{"url":"https://api.github.com/repos/google/oauth2client/pulls/comments/44456666","id":44456666,"diff_hunk":"@@ -0,0 +1,142 @@\n+# Copyright 2015 Google Inc.  All rights reserved.\n+#\n+# Licensed under the Apache License, Version 2.0 (the \"License\");\n+# you may not use this file except in compliance with the License.\n+# You may obtain a copy of the License at\n+#\n+#     http://www.apache.org/licenses/LICENSE-2.0\n+#\n+# Unless required by applicable law or agreed to in writing, software\n+# distributed under the License is distributed on an \"AS IS\" BASIS,\n+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+# See the License for the specific language governing permissions and\n+# limitations under the License.\n+\n+import hashlib\n+import json\n+import os\n+import pickle\n+\n+from django.core.urlresolvers import reverse\n+from django.http import HttpResponseBadRequest\n+from django.shortcuts import redirect\n+from oauth2client.client import FlowExchangeError, OAuth2WebServerFlow\n+from oauth2client.django_util import oauth2_settings\n+from oauth2client.django_util.signals import oauth2_authorized\n+from oauth2client.django_util.storage import get_storage\n+\n+\n+_CSRF_KEY = 'google_oauth2_csrf_token'\n+_FLOW_KEY = 'google_oauth2_flow_{0}'\n+\n+\n+def _make_flow(request, scopes, return_url=None):\n+    \"\"\"Creates a Web Server Flow\"\"\"\n+    # Generate a CSRF token to prevent malicious requests.\n+    csrf_token = hashlib.sha256(os.urandom(1024)).hexdigest()\n+\n+    request.session[_CSRF_KEY] = csrf_token\n+\n+    state = json.dumps({\n+        'csrf_token': csrf_token,\n+        'return_url': return_url,\n+    })\n+\n+    flow = OAuth2WebServerFlow(\n+        client_id=oauth2_settings.client_id,\n+        client_secret=oauth2_settings.client_secret,\n+        scope=scopes,\n+        state=state,\n+        redirect_uri=request.build_absolute_uri(\n+            reverse(\"google_oauth:callback\")))\n+\n+    flow_key = _FLOW_KEY.format(csrf_token)\n+    request.session[flow_key] = pickle.dumps(flow)\n+    return flow\n+\n+\n+def _get_flow_for_token(csrf_token, request):\n+    \"\"\" Looks up the flow in session to recover information about requested scopes \"\"\"\n+    flow_pickle = request.session.get(","path":"oauth2client/django_util/views.py","position":60,"original_position":60,"commit_id":"822754c0b23a03991d0204c00972aac91f9fcd07","original_commit_id":"822754c0b23a03991d0204c00972aac91f9fcd07","user":{"login":"waprin","id":1075173,"avatar_url":"https://avatars.githubusercontent.com/u/1075173?v=3","gravatar_id":"","url":"https://api.github.com/users/waprin","html_url":"https://github.com/waprin","followers_url":"https://api.github.com/users/waprin/followers","following_url":"https://api.github.com/users/waprin/following{/other_user}","gists_url":"https://api.github.com/users/waprin/gists{/gist_id}","starred_url":"https://api.github.com/users/waprin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/waprin/subscriptions","organizations_url":"https://api.github.com/users/waprin/orgs","repos_url":"https://api.github.com/users/waprin/repos","events_url":"https://api.github.com/users/waprin/events{/privacy}","received_events_url":"https://api.github.com/users/waprin/received_events","type":"User","site_admin":false},"body":"done in incoming commit","created_at":"2015-11-10T19:59:24Z","updated_at":"2015-11-10T19:59:24Z","html_url":"https://github.com/google/oauth2client/pull/332#discussion_r44456666","pull_request_url":"https://api.github.com/repos/google/oauth2client/pulls/332","_links":{"self":{"href":"https://api.github.com/repos/google/oauth2client/pulls/comments/44456666"},"html":{"href":"https://github.com/google/oauth2client/pull/332#discussion_r44456666"},"pull_request":{"href":"https://api.github.com/repos/google/oauth2client/pulls/332"}}},"pull_request":{"url":"https://api.github.com/repos/google/oauth2client/pulls/332","id":48517642,"html_url":"https://github.com/google/oauth2client/pull/332","diff_url":"https://github.com/google/oauth2client/pull/332.diff","patch_url":"https://github.com/google/oauth2client/pull/332.patch","issue_url":"https://api.github.com/repos/google/oauth2client/issues/332","number":332,"state":"open","locked":false,"title":"Add Django Util With Decorator and Views","user":{"login":"waprin","id":1075173,"avatar_url":"https://avatars.githubusercontent.com/u/1075173?v=3","gravatar_id":"","url":"https://api.github.com/users/waprin","html_url":"https://github.com/waprin","followers_url":"https://api.github.com/users/waprin/followers","following_url":"https://api.github.com/users/waprin/following{/other_user}","gists_url":"https://api.github.com/users/waprin/gists{/gist_id}","starred_url":"https://api.github.com/users/waprin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/waprin/subscriptions","organizations_url":"https://api.github.com/users/waprin/orgs","repos_url":"https://api.github.com/users/waprin/repos","events_url":"https://api.github.com/users/waprin/events{/privacy}","received_events_url":"https://api.github.com/users/waprin/received_events","type":"User","site_admin":false},"body":"This Django extension adds the views, decorators, and signals to oauth2client.\r\n\r\nThis is heavily based on the work @jonparrott did for oauth2client/flask_util.\r\n\r\nCurrently the only storage offered uses Django sessions. Based on issue #319 more storage options are planned along with integration to the existing CredentialsField in django_orm. \r\n\r\nThis adds an environment variable to the tox script. This might not be strictly necessary, but it did simplify the tests a lot, since Django settings get looked up at import time and cached so it's easiest if they have an environment variable pointing to an existing settings module when the tests are started.\r\n\r\nThis could have been squeezed into a single file, but  I spilt it into separate files based on existing Django extension conventions.","created_at":"2015-10-22T21:47:46Z","updated_at":"2015-11-10T19:59:24Z","closed_at":null,"merged_at":null,"merge_commit_sha":"6b10edb8f68086cbc2121beb8a5229232c6797be","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/google/oauth2client/pulls/332/commits","review_comments_url":"https://api.github.com/repos/google/oauth2client/pulls/332/comments","review_comment_url":"https://api.github.com/repos/google/oauth2client/pulls/comments{/number}","comments_url":"https://api.github.com/repos/google/oauth2client/issues/332/comments","statuses_url":"https://api.github.com/repos/google/oauth2client/statuses/822754c0b23a03991d0204c00972aac91f9fcd07","head":{"label":"waprin:django_util","ref":"django_util","sha":"822754c0b23a03991d0204c00972aac91f9fcd07","user":{"login":"waprin","id":1075173,"avatar_url":"https://avatars.githubusercontent.com/u/1075173?v=3","gravatar_id":"","url":"https://api.github.com/users/waprin","html_url":"https://github.com/waprin","followers_url":"https://api.github.com/users/waprin/followers","following_url":"https://api.github.com/users/waprin/following{/other_user}","gists_url":"https://api.github.com/users/waprin/gists{/gist_id}","starred_url":"https://api.github.com/users/waprin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/waprin/subscriptions","organizations_url":"https://api.github.com/users/waprin/orgs","repos_url":"https://api.github.com/users/waprin/repos","events_url":"https://api.github.com/users/waprin/events{/privacy}","received_events_url":"https://api.github.com/users/waprin/received_events","type":"User","site_admin":false},"repo":{"id":44128520,"name":"oauth2client","full_name":"waprin/oauth2client","owner":{"login":"waprin","id":1075173,"avatar_url":"https://avatars.githubusercontent.com/u/1075173?v=3","gravatar_id":"","url":"https://api.github.com/users/waprin","html_url":"https://github.com/waprin","followers_url":"https://api.github.com/users/waprin/followers","following_url":"https://api.github.com/users/waprin/following{/other_user}","gists_url":"https://api.github.com/users/waprin/gists{/gist_id}","starred_url":"https://api.github.com/users/waprin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/waprin/subscriptions","organizations_url":"https://api.github.com/users/waprin/orgs","repos_url":"https://api.github.com/users/waprin/repos","events_url":"https://api.github.com/users/waprin/events{/privacy}","received_events_url":"https://api.github.com/users/waprin/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/waprin/oauth2client","description":"This is a Python library for accessing resources protected by OAuth 2.0.","fork":true,"url":"https://api.github.com/repos/waprin/oauth2client","forks_url":"https://api.github.com/repos/waprin/oauth2client/forks","keys_url":"https://api.github.com/repos/waprin/oauth2client/keys{/key_id}","collaborators_url":"https://api.github.com/repos/waprin/oauth2client/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/waprin/oauth2client/teams","hooks_url":"https://api.github.com/repos/waprin/oauth2client/hooks","issue_events_url":"https://api.github.com/repos/waprin/oauth2client/issues/events{/number}","events_url":"https://api.github.com/repos/waprin/oauth2client/events","assignees_url":"https://api.github.com/repos/waprin/oauth2client/assignees{/user}","branches_url":"https://api.github.com/repos/waprin/oauth2client/branches{/branch}","tags_url":"https://api.github.com/repos/waprin/oauth2client/tags","blobs_url":"https://api.github.com/repos/waprin/oauth2client/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/waprin/oauth2client/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/waprin/oauth2client/git/refs{/sha}","trees_url":"https://api.github.com/repos/waprin/oauth2client/git/trees{/sha}","statuses_url":"https://api.github.com/repos/waprin/oauth2client/statuses/{sha}","languages_url":"https://api.github.com/repos/waprin/oauth2client/languages","stargazers_url":"https://api.github.com/repos/waprin/oauth2client/stargazers","contributors_url":"https://api.github.com/repos/waprin/oauth2client/contributors","subscribers_url":"https://api.github.com/repos/waprin/oauth2client/subscribers","subscription_url":"https://api.github.com/repos/waprin/oauth2client/subscription","commits_url":"https://api.github.com/repos/waprin/oauth2client/commits{/sha}","git_commits_url":"https://api.github.com/repos/waprin/oauth2client/git/commits{/sha}","comments_url":"https://api.github.com/repos/waprin/oauth2client/comments{/number}","issue_comment_url":"https://api.github.com/repos/waprin/oauth2client/issues/comments{/number}","contents_url":"https://api.github.com/repos/waprin/oauth2client/contents/{+path}","compare_url":"https://api.github.com/repos/waprin/oauth2client/compare/{base}...{head}","merges_url":"https://api.github.com/repos/waprin/oauth2client/merges","archive_url":"https://api.github.com/repos/waprin/oauth2client/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/waprin/oauth2client/downloads","issues_url":"https://api.github.com/repos/waprin/oauth2client/issues{/number}","pulls_url":"https://api.github.com/repos/waprin/oauth2client/pulls{/number}","milestones_url":"https://api.github.com/repos/waprin/oauth2client/milestones{/number}","notifications_url":"https://api.github.com/repos/waprin/oauth2client/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/waprin/oauth2client/labels{/name}","releases_url":"https://api.github.com/repos/waprin/oauth2client/releases{/id}","created_at":"2015-10-12T19:12:47Z","updated_at":"2015-10-12T19:12:50Z","pushed_at":"2015-11-04T18:53:47Z","git_url":"git://github.com/waprin/oauth2client.git","ssh_url":"git@github.com:waprin/oauth2client.git","clone_url":"https://github.com/waprin/oauth2client.git","svn_url":"https://github.com/waprin/oauth2client","homepage":"","size":23348,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":1,"forks":0,"open_issues":1,"watchers":0,"default_branch":"master"}},"base":{"label":"google:master","ref":"master","sha":"311a53fbcae550526a74057f27cb9df73a0af009","user":{"login":"google","id":1342004,"avatar_url":"https://avatars.githubusercontent.com/u/1342004?v=3","gravatar_id":"","url":"https://api.github.com/users/google","html_url":"https://github.com/google","followers_url":"https://api.github.com/users/google/followers","following_url":"https://api.github.com/users/google/following{/other_user}","gists_url":"https://api.github.com/users/google/gists{/gist_id}","starred_url":"https://api.github.com/users/google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/google/subscriptions","organizations_url":"https://api.github.com/users/google/orgs","repos_url":"https://api.github.com/users/google/repos","events_url":"https://api.github.com/users/google/events{/privacy}","received_events_url":"https://api.github.com/users/google/received_events","type":"Organization","site_admin":false},"repo":{"id":14211461,"name":"oauth2client","full_name":"google/oauth2client","owner":{"login":"google","id":1342004,"avatar_url":"https://avatars.githubusercontent.com/u/1342004?v=3","gravatar_id":"","url":"https://api.github.com/users/google","html_url":"https://github.com/google","followers_url":"https://api.github.com/users/google/followers","following_url":"https://api.github.com/users/google/following{/other_user}","gists_url":"https://api.github.com/users/google/gists{/gist_id}","starred_url":"https://api.github.com/users/google/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/google/subscriptions","organizations_url":"https://api.github.com/users/google/orgs","repos_url":"https://api.github.com/users/google/repos","events_url":"https://api.github.com/users/google/events{/privacy}","received_events_url":"https://api.github.com/users/google/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/google/oauth2client","description":"This is a Python library for accessing resources protected by OAuth 2.0.","fork":false,"url":"https://api.github.com/repos/google/oauth2client","forks_url":"https://api.github.com/repos/google/oauth2client/forks","keys_url":"https://api.github.com/repos/google/oauth2client/keys{/key_id}","collaborators_url":"https://api.github.com/repos/google/oauth2client/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/google/oauth2client/teams","hooks_url":"https://api.github.com/repos/google/oauth2client/hooks","issue_events_url":"https://api.github.com/repos/google/oauth2client/issues/events{/number}","events_url":"https://api.github.com/repos/google/oauth2client/events","assignees_url":"https://api.github.com/repos/google/oauth2client/assignees{/user}","branches_url":"https://api.github.com/repos/google/oauth2client/branches{/branch}","tags_url":"https://api.github.com/repos/google/oauth2client/tags","blobs_url":"https://api.github.com/repos/google/oauth2client/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/google/oauth2client/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/google/oauth2client/git/refs{/sha}","trees_url":"https://api.github.com/repos/google/oauth2client/git/trees{/sha}","statuses_url":"https://api.github.com/repos/google/oauth2client/statuses/{sha}","languages_url":"https://api.github.com/repos/google/oauth2client/languages","stargazers_url":"https://api.github.com/repos/google/oauth2client/stargazers","contributors_url":"https://api.github.com/repos/google/oauth2client/contributors","subscribers_url":"https://api.github.com/repos/google/oauth2client/subscribers","subscription_url":"https://api.github.com/repos/google/oauth2client/subscription","commits_url":"https://api.github.com/repos/google/oauth2client/commits{/sha}","git_commits_url":"https://api.github.com/repos/google/oauth2client/git/commits{/sha}","comments_url":"https://api.github.com/repos/google/oauth2client/comments{/number}","issue_comment_url":"https://api.github.com/repos/google/oauth2client/issues/comments{/number}","contents_url":"https://api.github.com/repos/google/oauth2client/contents/{+path}","compare_url":"https://api.github.com/repos/google/oauth2client/compare/{base}...{head}","merges_url":"https://api.github.com/repos/google/oauth2client/merges","archive_url":"https://api.github.com/repos/google/oauth2client/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/google/oauth2client/downloads","issues_url":"https://api.github.com/repos/google/oauth2client/issues{/number}","pulls_url":"https://api.github.com/repos/google/oauth2client/pulls{/number}","milestones_url":"https://api.github.com/repos/google/oauth2client/milestones{/number}","notifications_url":"https://api.github.com/repos/google/oauth2client/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/google/oauth2client/labels{/name}","releases_url":"https://api.github.com/repos/google/oauth2client/releases{/id}","created_at":"2013-11-07T18:03:04Z","updated_at":"2015-11-10T06:42:59Z","pushed_at":"2015-11-04T18:53:47Z","git_url":"git://github.com/google/oauth2client.git","ssh_url":"git@github.com:google/oauth2client.git","clone_url":"https://github.com/google/oauth2client.git","svn_url":"https://github.com/google/oauth2client","homepage":"","size":25436,"stargazers_count":265,"watchers_count":265,"language":"Python","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":true,"forks_count":135,"mirror_url":null,"open_issues_count":57,"forks":135,"open_issues":57,"watchers":265,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/google/oauth2client/pulls/332"},"html":{"href":"https://github.com/google/oauth2client/pull/332"},"issue":{"href":"https://api.github.com/repos/google/oauth2client/issues/332"},"comments":{"href":"https://api.github.com/repos/google/oauth2client/issues/332/comments"},"review_comments":{"href":"https://api.github.com/repos/google/oauth2client/pulls/332/comments"},"review_comment":{"href":"https://api.github.com/repos/google/oauth2client/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/google/oauth2client/pulls/332/commits"},"statuses":{"href":"https://api.github.com/repos/google/oauth2client/statuses/822754c0b23a03991d0204c00972aac91f9fcd07"}}}}