1111import base64
1212from typing import Any
1313
14+ import jwt
15+ from requests .models import HTTPError
16+
1417import flask
1518import werkzeug
1619from flask import Flask , request , redirect , session , render_template , send_from_directory , jsonify
5154 + '&code=%s'
5255
5356_GITHUB_AUTH_URI = 'https://github.com/login/oauth/authorize' \
54- + '?client_id=%s' \
57+ + '?client_id=%s' \
5558 + '&state=%s'
5659_GITHUB_TOKEN_URI = 'https://github.com/login/oauth/access_token' \
5760 + '?client_id=%s' \
@@ -168,19 +171,29 @@ def _github_landing() -> tuple[str, int]:
168171 (APP .config ['GITHUB_CLIENT_ID' ], APP .config ['GITHUB_SECRET' ],
169172 request .args .get ('code' )),
170173 headers = {'Accept' : 'application/json' },
171- timeout = APP .config ['REQUEST_TIMEOUT' ],
172- )
173- token = resp .json ()['access_token' ]
174+ timeout = APP .config ['REQUEST_TIMEOUT' ])
175+ try :
176+ resp .raise_for_status ()
177+ except HTTPError as e :
178+ print ('response:' , resp .json ())
179+ raise e
180+
181+ resp_json = resp .json ()
182+ token = resp_json ['access_token' ]
174183 header = {
175184 'Authorization' : 'token ' + token ,
176185 'Accept' : 'application/vnd.github.v3+json'
177186 }
178187
179- user_resp = requests .get (
180- 'https://api.github.com/user' ,
181- headers = header ,
182- timeout = APP .config ['REQUEST_TIMEOUT' ],
183- )
188+ user_resp = requests .get ('https://api.github.com/user' ,
189+ headers = header ,
190+ timeout = APP .config ['REQUEST_TIMEOUT' ])
191+ try :
192+ user_resp .raise_for_status ()
193+ except HTTPError as e :
194+ print ('response:' , user_resp .json ())
195+ raise e
196+
184197 user_resp_json = user_resp .json ()
185198
186199 github_username = user_resp_json ['login' ]
@@ -194,20 +207,88 @@ def _github_landing() -> tuple[str, int]:
194207 return render_template ('callback.html' ), 200
195208
196209
210+ def _get_github_jwt () -> str :
211+ signing_key = APP .config ["GITHUB_APP_PRIVATE_KEY" ]
212+
213+ payload = {
214+ 'iat' : int (time .time ()),
215+ 'exp' : int (time .time () + 600 ),
216+ 'iss' : APP .config ['GITHUB_APP_ID' ],
217+ }
218+
219+ encoded_jwt = jwt .encode (payload , signing_key , algorithm = 'RS256' )
220+
221+ return encoded_jwt
222+
223+
224+ def _auth_github_org () -> str :
225+ jwt_auth = _get_github_jwt ()
226+
227+ headers = {
228+ 'Accept' : 'application/vnd.github.v3+json' ,
229+ 'Authorization' : f'Bearer { jwt_auth } ' ,
230+ }
231+
232+ org_installation_resp = requests .get (
233+ 'https://api.github.com/orgs/ComputerScienceHouse/installation' ,
234+ headers = headers ,
235+ timeout = APP .config ['REQUEST_TIMEOUT' ])
236+ try :
237+ org_installation_resp .raise_for_status ()
238+ except HTTPError as e :
239+ print ('response:' , org_installation_resp .json ())
240+ raise e
241+
242+ org_installation_json = org_installation_resp .json ()
243+ org_installation_id = org_installation_json ['id' ]
244+
245+ org_token_resp = requests .post (
246+ f'https://api.github.com/app/installations/{ org_installation_id } /access_tokens' ,
247+ headers = headers ,
248+ timeout = APP .config ['REQUEST_TIMEOUT' ])
249+ try :
250+ org_token_resp .raise_for_status ()
251+ except HTTPError as e :
252+ print ('response:' , org_token_resp .json ())
253+ raise e
254+
255+ org_token_json = org_token_resp .json ()
256+ org_token = org_token_json ['token' ]
257+
258+ return org_token
259+
260+
197261def _link_github (github_username : str , github_id : str , member : Any ) -> None :
198262 """
199263 Puts a member's github into LDAP and adds them to the org.
200264 :param github_username: the user's github username
201265 :param github_id: the user's github id
202266 :param member: the member's LDAP object
203267 """
204- payload = {'invitee_id' : github_id }
205- requests .post (
268+ org_token = _auth_github_org ()
269+
270+ payload = {
271+ 'org' : 'ComputerScienceHouse' ,
272+ 'invitee_id' : github_id ,
273+ 'role' : 'direct_member'
274+ }
275+
276+ github_org_headers = {
277+ 'Accept' : 'application/vnd.github.v3+json' ,
278+ 'Authorization' : f'Token { org_token } ' ,
279+ }
280+
281+ resp = requests .post (
206282 'https://api.github.com/orgs/ComputerScienceHouse/invitations' ,
207- headers = _ORG_HEADER ,
208- data = payload ,
209- timeout = APP .config ['REQUEST_TIMEOUT' ],
210- )
283+ headers = github_org_headers ,
284+ json = payload ,
285+ timeout = APP .config ['REQUEST_TIMEOUT' ])
286+ try :
287+ resp .raise_for_status ()
288+ except HTTPError as e :
289+ print ('response:' , resp .json ())
290+ raise e
291+
211292 member .github = github_username
212293
213294
@@ -217,12 +298,27 @@ def _revoke_github() -> werkzeug.Response:
217298 """ Clear's a member's github in LDAP and removes them from the org. """
218299 uid = str (session ['userinfo' ].get ('preferred_username' , '' ))
219300 member = _LDAP .get_member (uid , uid = True )
220- requests .delete (
301+
302+ org_token = _auth_github_org ()
303+
304+ headers = {
305+ 'Accept' : 'application/vnd.github.v3+json' ,
306+ 'Authorization' : f'Token { org_token } ' ,
307+ }
308+
309+ resp = requests .delete (
221310 'https://api.github.com/orgs/ComputerScienceHouse/members/' +
222311 member .github ,
223- headers = _ORG_HEADER ,
312+ headers = headers ,
224313 timeout = APP .config ['REQUEST_TIMEOUT' ],
225314 )
315+
316+ try :
317+ resp .raise_for_status ()
318+ except HTTPError as e :
319+ print ('response:' , resp .json ())
320+ raise e
321+
226322 member .github = None
227323 return jsonify (success = True )
228324
0 commit comments