-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.coffee
226 lines (194 loc) · 7.04 KB
/
index.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
gh = do ->
error = ''
xhrWithAuth = (method, url, interactive, callback) ->
retry = true
access_token = undefined
getToken = ->
tokenFetcher.getToken interactive, (error, token) ->
if error
callback error
return
access_token = token
requestStart()
return
return
requestStart = ->
xhr = new XMLHttpRequest
xhr.open method, url
xhr.setRequestHeader 'Authorization', 'Bearer ' + access_token
xhr.onload = requestComplete
xhr.send()
return
requestComplete = ->
if (@status < 200 or @status >= 300) and retry
retry = false
tokenFetcher.removeCachedToken access_token
access_token = null
getToken()
else
callback null, @status, @response
return
getToken()
return
getUserInfo = (interactive) ->
xhrWithAuth 'GET', 'https://api.github.com/user', interactive, onUserInfoFetched
return
# Functions updating the User Interface:
showButton = (button) ->
button?.style.display = 'inline'
button?.disabled = false
return
handleError = (error) ->
disableButton = (button) ->
button?.disabled = true
return
onUserInfoFetched = (error, status, response) ->
if !error and status == 200
user_info = JSON.parse(response)
populateUserInfo user_info
fetchUserRepos user_info['repos_url']
else
handleError error
return
populateUserInfo = (user_info) ->
elem = user_info_div
nameElem = document.createElement('div')
nameElem.innerHTML = '<b>Hello ' + user_info.name + '</b><br>' + 'Your github page is: ' + user_info.html_url
elem?.appendChild nameElem
return
fetchUserRepos = (repoUrl) ->
xhrWithAuth 'GET', repoUrl, false, onUserReposFetched
return
onUserReposFetched = (error, status, response) ->
if !error and status == 200
user_repos = JSON.parse(response)
user_repos.forEach (repo) ->
if repo.private
elem.value += '[private repo]'
else
elem.value += repo.name
elem.value += '\n'
return
else
return
# Handlers for the buttons's onclick events.
interactiveSignIn = (next) ->
disableButton signin_button
tokenFetcher.getToken true, (error, access_token) ->
next error, access_token
revokeToken = ->
# We are opening the web page that allows user to revoke their token.
# And then clear the user interface, showing the Sign in button only.
# If the user revokes the app authorization, they will be prompted to log
# in again. If the user dismissed the page they were presented with,
# Sign in button will simply sign them in.
localStorage.removeItem('access_token')
tokenFetcher.getToken false, (error, access_token) ->
tokenFetcher.removeCachedToken access_token
return
'use strict'
signin_button = undefined
revoke_button = undefined
user_info_div = undefined
tokenFetcher = do ->
# Replace clientId and clientSecret with values obtained by you for your
# application https://github.com/settings/applications.
clientId = '4d7be2147641f42a5218'
clientSecret = 'd01fbd103a93e0b3bc5913a9234eb1738b55977b'
redirectUri = chrome.identity.getRedirectURL('provider_cb')
redirectRe = new RegExp(redirectUri + '[#?](.*)')
access_token = null
{
getToken: (interactive, callback) ->
# In case we already have an access_token cached, simply return it.
parseRedirectFragment = (fragment) ->
pairs = fragment.split(/&/)
values = {}
pairs.forEach (pair) ->
nameval = pair.split(RegExp('='))
values[nameval[0]] = nameval[1]
return
values
handleProviderResponse = (values) ->
if values.hasOwnProperty('access_token')
setAccessToken values.access_token
else if values.hasOwnProperty('code')
exchangeCodeForToken values.code
else
callback new Error('Neither access_token nor code avialable.')
return
exchangeCodeForToken = (code) ->
xhr = new XMLHttpRequest
xhr.open 'GET', 'https://github.com/login/oauth/access_token?' + 'client_id=' + clientId + '&client_secret=' + clientSecret + '&redirect_uri=' + redirectUri + '&code=' + code + '&scope=user,repo'
xhr.setRequestHeader 'Content-Type', 'application/x-www-form-urlencoded'
xhr.setRequestHeader 'Accept', 'application/json'
xhr.onload = ->
# When exchanging code for token, the response comes as json, which
# can be easily parsed to an object.
if @status == 200
response = JSON.parse(@responseText)
if response.hasOwnProperty('access_token')
setAccessToken response.access_token
else
callback new Error('Cannot obtain access_token from code.')
else
callback new Error('Code exchange failed')
return
xhr.send()
return
setAccessToken = (token) ->
access_token = token
localStorage['access_token'] = token
callback null, access_token
return
access_token ?= localStorage['access_token']
if access_token
callback null, access_token
return
options =
'interactive': interactive
'url': 'https://github.com/login/oauth/authorize' + '?client_id=' + clientId + '&redirect_uri=' + encodeURIComponent(redirectUri) + '&scope=user,repo'
chrome.identity.launchWebAuthFlow options, (redirectUri) ->
if chrome.runtime.lastError
callback new Error(chrome.runtime.lastError)
return
# Upon success the response is appended to redirectUri, e.g.
# https://{app_id}.chromiumapp.org/provider_cb#access_token={value}
# &refresh_token={value}
# or:
# https://{app_id}.chromiumapp.org/provider_cb#code={value}
matches = redirectUri.match(redirectRe)
if matches and matches.length > 1
handleProviderResponse parseRedirectFragment(matches[1])
else
callback new Error('Invalid redirect URI')
return
return
removeCachedToken: (token_to_remove) ->
if access_token == token_to_remove
localStorage.removeItem('access_token')
access_token = null
return
}
{
error: error
tokenFetcher: tokenFetcher
revokeToken: revokeToken
xhrWithAuth: xhrWithAuth
interactiveSignIn: interactiveSignIn
revokeToken: revokeToken
getUserInfo: getUserInfo
onload: ->
###
signin_button = document.querySelector('#signin');
signin_button?.onclick = interactiveSignIn;
revoke_button = document.querySelector('#revoke');
revoke_button?.onclick = revokeToken;
user_info_div = document.querySelector('#user_info');
showButton(signin_button);
getUserInfo(false);
###
}
window.gh = gh;
# ---
# generated by js2coffee 2.0.3