Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit978d8c2

Browse files
committed
Merge pull requestsigmavirus24#167 from sigmavirus24/feature-two-factor-auth
Feature: Two factor auth
2 parents5b2a9f1 +824e4d5 commit978d8c2

File tree

11 files changed

+176
-16
lines changed

11 files changed

+176
-16
lines changed

‎.travis.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ python:
66
-3.3
77
-pypy
88
# # command to run tests, e.g. python setup.py test
9+
before_script:pip install -r dev-requirements.txt
910
script:make travis
1011
notifications:
1112
on_success:change

‎HISTORY.rst‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
History/Changelog
22
=================
33

4+
0.8.0: 2013-xx-xx
5+
-----------------
6+
7+
- Use Betamax to start recording integration tests
8+
9+
- Add support for Releases API
10+
11+
- Add support for Feeds API
12+
13+
- Add support for Two-Factor Authentication via the API
14+
15+
- Switch to requests >= 2.0
16+
417
0.7.1: 2013-09-30
518
-----------------
619

‎dev-requirements.txt‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
requests==1.2.3
1+
requests>=2.0.0,<=3.0.0
22
uritemplate.py==0.2.0
33
#coverage==3.5.2
44
mock==1.0.1
55
pytest==2.3.5
66
wheel==0.21.0
7-
betamax==0.1.5
7+
git+git://github.com/sigmavirus24/betamax

‎github3/github.py‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -821,7 +821,8 @@ def key(self, id_num):
821821
json=self._json(self._get(url),200)
822822
returnKey(json,self)ifjsonelseNone
823823

824-
deflogin(self,username=None,password=None,token=None):
824+
deflogin(self,username=None,password=None,token=None,
825+
two_factor_callback=None):
825826
"""Logs the user into GitHub for protected API calls.
826827
827828
:param str username: (optional)
@@ -833,6 +834,9 @@ def login(self, username=None, password=None, token=None):
833834
eliftoken:
834835
self._session.token_auth(token)
835836

837+
# The Session method handles None for free.
838+
self._session.two_factor_auth_callback(two_factor_callback)
839+
836840
defmarkdown(self,text,mode='',context='',raw=False):
837841
"""Render an arbitrary markdown document.
838842

‎github3/session.py‎

Lines changed: 46 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
importrequests
22

3+
fromcollectionsimportCallable
34
fromgithub3import__version__
45
fromloggingimportgetLogger
56

67
__url_cache__= {}
78
__logs__=getLogger(__package__)
89

910

11+
defrequires_2fa(response):
12+
if (response.status_code==401and'X-GitHub-OTP'inresponse.headers
13+
and'required'inresponse.headers['X-GitHub-OTP']):
14+
returnTrue
15+
returnFalse
16+
17+
1018
classGitHubSession(requests.Session):
1119
def__init__(self):
1220
super(GitHubSession,self).__init__()
@@ -21,6 +29,7 @@ def __init__(self):
2129
'User-Agent':'github3.py/{0}'.format(__version__),
2230
})
2331
self.base_url='https://api.github.com'
32+
self.two_factor_auth_cb=None
2433

2534
defbasic_auth(self,username,password):
2635
"""Set the Basic Auth credentials on this Session.
@@ -45,6 +54,43 @@ def build_url(self, *args, **kwargs):
4554
__url_cache__[key]='/'.join(parts)
4655
return__url_cache__[key]
4756

57+
defhandle_two_factor_auth(self,args,kwargs):
58+
headers=kwargs.pop('headers', {})
59+
headers.update({
60+
'X-GitHub-OTP':str(self.two_factor_auth_cb())
61+
})
62+
kwargs.update(headers=headers)
63+
returnsuper(GitHubSession,self).request(*args,**kwargs)
64+
65+
defoauth2_auth(self,client_id,client_secret):
66+
"""Use OAuth2 for authentication.
67+
68+
It is suggested you install requests-oauthlib to use this.
69+
70+
:param str client_id: Client ID retrieved from GitHub
71+
:param str client_secret: Client secret retrieved from GitHub
72+
"""
73+
raiseNotImplementedError('These features are not implemented yet')
74+
75+
defrequest(self,*args,**kwargs):
76+
response=super(GitHubSession,self).request(*args,**kwargs)
77+
ifrequires_2fa(response)andself.two_factor_auth_cb:
78+
# No need to flatten and re-collect the args in
79+
# handle_two_factor_auth
80+
new_response=self.handle_two_factor_auth(args,kwargs)
81+
new_response.history.append(response)
82+
response=new_response
83+
returnresponse
84+
85+
deftwo_factor_auth_callback(self,callback):
86+
ifnotcallback:
87+
return
88+
89+
ifnotisinstance(callback,Callable):
90+
raiseValueError('Your callback should be callable')
91+
92+
self.two_factor_auth_cb=callback
93+
4894
deftoken_auth(self,token):
4995
"""Use an application token for authentication.
5096
@@ -57,13 +103,3 @@ def token_auth(self, token):
57103
self.headers.update({
58104
'Authorization':'token {0}'.format(token)
59105
})
60-
61-
defoauth2_auth(self,client_id,client_secret):
62-
"""Use OAuth2 for authentication.
63-
64-
It is suggested you install requests-oauthlib to use this.
65-
66-
:param str client_id: Client ID retrieved from GitHub
67-
:param str client_secret: Client secret retrieved from GitHub
68-
"""
69-
raiseNotImplementedError('These features are not implemented yet')

‎setup.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"github3.issues",
1717
]
1818

19-
kwargs['tests_require']= ['mock==1.0.1','betamax==0.1.5','pytest']
19+
kwargs['tests_require']= ['mock==1.0.1','betamax','pytest']
2020
ifsys.version_info< (3,0):
2121
kwargs['tests_require'].append('unittest2==0.5.1')
2222
packages.append('tests')
@@ -25,7 +25,7 @@
2525
os.system("python setup.py bdist_wheel sdist upload")
2626
sys.exit()
2727

28-
requires.extend(["requests >=1.2.3","uritemplate.py >= 0.2.0"])
28+
requires.extend(["requests >=2.0","uritemplate.py >= 0.2.0"])
2929

3030
__version__=''
3131
withopen('github3/__init__.py','r')asfd:
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"http_interactions": [{"request": {"body": "", "headers": {"Accept-Encoding": "gzip, deflate, compress", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.8.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic <BASIC_AUTH>"}, "method": "GET", "uri": "https://api.github.com/users/sigmavirus24"}, "response": {"body": {"string": "{\"message\":\"Must specify two-factor authentication OTP code.\",\"documentation_url\":\"http://developer.github.com/v3/auth#working-with-two-factor-authentication\"}", "encoding": "utf-8"}, "headers": {"status": "401 Unauthorized", "x-ratelimit-remaining": "57", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "access-control-expose-headers": "ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes", "x-github-request-id": "48A0B729:5402:3028482:52969FEC", "x-github-otp": "required; app", "content-length": "159", "server": "GitHub.com", "x-ratelimit-limit": "60", "access-control-allow-credentials": "true", "date": "Thu, 28 Nov 2013 01:44:12 GMT", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1385606471"}, "url": "https://api.github.com/users/sigmavirus24", "status_code": 401}, "recorded_at": "2013-11-28T01:44:13"}, {"request": {"body": "", "headers": {"Accept-Encoding": "gzip, deflate, compress", "X-GitHub-OTP": "862478", "Accept": "application/vnd.github.v3.full+json", "User-Agent": "github3.py/0.8.0", "Accept-Charset": "utf-8", "Content-Type": "application/json", "Authorization": "Basic <BASIC_AUTH>"}, "method": "GET", "uri": "https://api.github.com/users/sigmavirus24"}, "response": {"body": {"base64_string": "H4sIAAAAAAAAA51UXWvbMBT9K8XQPSWRvxI7hrIvGPRhbx2DvYRrSXZEFctIcrIsdL99R07ataFQUgjE2Pece+65H4dIm1Z1URU51W5oq+zg0jyaREpEVZrHZRZPItqSJ7sarEbc2vveVYwls9YeP8y42bDjI+NJXmbzhSiXzTKdy8UyTYqyljIRy4x4U3wUNyPBdfb5Ov2GnxKy84qbzs1a5ddDHdjwPqciKRZ5nOVckCyLIi/zWhZpkZQ1zdPFrO/aD/bmN6Q+6lgFzdFbCgB4WQj16llqNjhpHTtzY+03+qz+/2rPgxujtdmB5QzxZiL2hITI47Pq2neyAHlgxq8lGoeSHoJRyvnLRY2oAwt/cDjwOEyDleJiYSccZO06KDowK3szEg6141b1XmEOLqd9jgabsS116g+9jw1oB5Ig7XIpIwpoucVUXw4/wg6st2pLfB+ssZJLtYXZ76Q8w4PR73uJPfmBoQjWKy9XJDbhBjSknZxEHW1CwC11V1+NFeS4QSDWsqdujw9fZCf2O2PvQ6U17sfpKuAo7HY77G+r1bjG7C8WeyRgY9gEx4aPbQHiOwnlTDe5+nkbDNuQCtcFu9w05LnRUNSa7SccJaUDGYLWykqqNcSdlNbKRFU3aD2J+qHWiq+ODajm5eMCYQ2jaoEj9rRPuGsLlAMqD1vJI2saJ/E0zqdJfBfnVVxUWfoL+YZevIjJpkkyTYu7NKnyrMrmIcYbT3o1NgxGntIjXRhx8cp7FH2PhaQWVWS4Y3lwVmuqjSVvgliAe02w6PDYicZKGVrVEw+ouEhjBL0CO1Px8PAP0MDI0N8FAAA=", "encoding": "utf-8"}, "headers": {"status": "200 OK", "x-ratelimit-remaining": "4930", "x-github-media-type": "github.v3; param=full; format=json", "x-content-type-options": "nosniff", "access-control-expose-headers": "ETag, Link, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes", "transfer-encoding": "chunked", "x-github-request-id": "48A0B729:5402:3028B0A:52969FEC", "content-encoding": "gzip", "vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "server": "GitHub.com", "cache-control": "private, max-age=60, s-maxage=60", "last-modified": "Wed, 27 Nov 2013 21:43:35 GMT", "x-ratelimit-limit": "5000", "etag": "\"678c237081785fa8c850d78a6779b7aa\"", "access-control-allow-credentials": "true", "date": "Thu, 28 Nov 2013 01:44:16 GMT", "access-control-allow-origin": "*", "content-type": "application/json; charset=utf-8", "x-ratelimit-reset": "1385603853"}, "url": "https://api.github.com/users/sigmavirus24", "status_code": 200}, "recorded_at": "2013-11-28T01:44:16"}], "recorded_with": "betamax"}

‎tests/integration/test_session.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
importgithub3
2+
3+
from .helperimportIntegrationHelper
4+
5+
6+
classTestGitHubSession(IntegrationHelper):
7+
deftest_two_factor_authentication_works(self):
8+
two_factor_auth=lambda:'862478'
9+
self.basic_login()
10+
self.gh.login(two_factor_callback=two_factor_auth)
11+
12+
cassette_name=self.cassette_name('two_factor_authentication')
13+
assertisinstance(self.session,github3.session.GitHubSession)
14+
15+
match= ['method','uri','headers']
16+
withself.recorder.use_cassette(cassette_name,
17+
match_requests_on=match):
18+
r=self.session.get('https://api.github.com/users/sigmavirus24')
19+
assertr.status_code==200

‎tests/unit/helper.py‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ def create_session_mock(self, *args):
3535

3636
defsetUp(self):
3737
self.session=self.create_session_mock()
38-
self.instance=self.described_class(self.example_data,self.session)
38+
ifself.example_data:
39+
self.instance=self.described_class(self.example_data,
40+
self.session)
41+
else:
42+
self.instance=self.described_class()
43+
self.instance._session=self.session
3944
# Proxy the build_url method to the class so it can build the URL and
4045
# we can assert things about the call that will be attempted to the
4146
# internet

‎tests/unit/test_github.py‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
fromgithub3.githubimportGitHub
2+
3+
from .helperimportUnitHelper
4+
5+
6+
classTestGitHub(UnitHelper):
7+
described_class=GitHub
8+
example_data=None
9+
10+
deftest_two_factor_login(self):
11+
self.instance.login('username','password',
12+
two_factor_callback=lambda*args:'foo')
13+
14+
deftest_can_login_without_two_factor_callback(self):
15+
self.instance.login('username','password')
16+
self.instance.login(token='token')

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp