13
13
from ..ext .identitytoolkit import Gitkit
14
14
from itsdangerous import URLSafeTimedSerializer
15
15
16
- from ..model import Account , Repository , Roles , Site , db
16
+ from ..model import Account , Challenge , Repository , Roles , Site , Sites , db
17
17
from .base import app , mailgun , jsonp
18
18
19
19
@@ -70,6 +70,8 @@ def authorization_required(*roles):
70
70
def decorator (func ):
71
71
@wraps (func )
72
72
def wrapper (** values ):
73
+ if not current_user .email_verified :
74
+ abort (403 )
73
75
site_id = values ['site_id' ]
74
76
synchronize (site_id )
75
77
needs = [(role , site_id ) for role in roles ]
@@ -84,26 +86,11 @@ def permission_denied(exc):
84
86
return 'Forbidden' , 403
85
87
86
88
87
- @app .template_global ()
88
- def auth_url_for (endpoint , ** values ):
89
- if endpoint == 'widget' :
90
- if app .config ['DEVELOPMENT' ]:
91
- values .setdefault ('next' , request .url )
92
- return url_for ('auth.widget' , ** values )
93
- next = values .pop ('next' , request .url )
94
- values ['next' ] = url_for (
95
- 'auth.sign_in_success' ,
96
- next = next ,
97
- _external = True )
98
- return url_for ('auth.widget' , ** values )
99
- if endpoint == 'sign_out' :
100
- return url_for ('auth.sign_out' , ** values )
101
- raise Exception ('Invalid enpoint: {}' .format (endpoint ))
102
-
103
-
104
89
@blueprint .route ('/widget' , methods = {'GET' , 'POST' })
105
90
def widget ():
106
- if app .config ['DEVELOPMENT' ] and request .method == 'POST' :
91
+ if app .config ['DEVELOPMENT' ]:
92
+ if request .method == 'GET' :
93
+ return render_template ('auth/widget.html' )
107
94
email = request .form ['email' ]
108
95
account = Account .query .filter_by (email = email ).one_or_none ()
109
96
if account is None :
@@ -115,43 +102,40 @@ def widget():
115
102
db .session .flush ()
116
103
login_user (account )
117
104
db .session .commit ()
118
- return redirect (request .args .get ('next' , request .url_root ))
119
- if not app .config ['DEVELOPMENT' ]:
120
- url_adapter = _request_ctx_stack .top .url_adapter
121
- next = request .args .get ('next' )
122
- if next is not None :
123
- url = urlparse (next )
124
- if url .netloc != request .host :
125
- abort (400 )
126
- endpoint , __ = url_adapter .match (url .path , 'GET' )
127
- if endpoint != 'auth.sign_in_success' :
128
- abort (400 )
129
- query = parse_qs (url .query )
130
- next = query .get ('next' )
131
- if next is None :
132
- abort (400 )
133
- url = urlparse (next [0 ])
134
- if url .netloc != request .host :
135
- abort (400 )
136
- endpoint , values = url_adapter .match (url .path , 'GET' )
137
- if endpoint != 'auth.site_authenticated' :
138
- abort (400 )
139
- site_id = values ['site_id' ]
140
- site = synchronize (site_id )
141
- options = site .gitkit_options
142
- elif request .args .get ('mode' ) == 'select' :
143
- return render_template (
144
- 'auth/close-window.html' ,
145
- message = 'You can only sign in to a specific site.' )
146
- else :
147
- options = None
148
- else :
149
- options = None
150
- return render_template ('auth/widget.html' , options = options or {})
105
+ return render_template ('auth/close-window.html' , message = 'You have signed in.' )
106
+ if request .args .get ('mode' ) != 'select' :
107
+ return render_template ('auth/widget.html' , options = {})
108
+ url_adapter = _request_ctx_stack .top .url_adapter
109
+ next = request .args .get ('next' )
110
+ if next :
111
+ url = urlparse (next )
112
+ if url .netloc != request .host :
113
+ abort (400 )
114
+ endpoint , values = url_adapter .match (url .path , 'GET' )
115
+ if endpoint != 'auth.sign_in_success' :
116
+ abort (400 )
117
+ site = synchronize (values ['site_id' ])
118
+ return render_template ('auth/widget.html' , options = site .gitkit_options )
119
+ url = urlparse (request .referrer )
120
+ if url .netloc != request .host :
121
+ abort (400 )
122
+ endpoint , __ = url_adapter .match (url .path , 'GET' )
123
+ if endpoint != request .endpoint :
124
+ abort (400 )
125
+ oob_code = parse_qs (url .query ).get ('oobCode' )
126
+ if not oob_code or len (oob_code ) != 1 :
127
+ abort (400 )
128
+ challenge = Challenge .query .get (oob_code [0 ])
129
+ if challenge is None :
130
+ abort (400 )
131
+ base_url = Sites (challenge .site_id ).get_base_url ()
132
+ if not base_url .endswith ('/' ):
133
+ base_url += '/'
134
+ return redirect ('{}#sign-in' .format (base_url ))
151
135
152
136
153
- @blueprint .route ('/sign-in-success' )
154
- def sign_in_success ():
137
+ @blueprint .route ('/site/<site_id>/ sign-in-success' )
138
+ def sign_in_success (site_id ):
155
139
token = gitkit .verify_token ()
156
140
if token is None :
157
141
abort (400 )
@@ -160,21 +144,27 @@ def sign_in_success():
160
144
if account is None :
161
145
account = Account (id = token ['id' ])
162
146
db .session .add (account )
163
- account .email = gitkit_account ['email' ]
147
+ email = gitkit_account ['email' ]
148
+ account .email = email
164
149
account .email_verified = gitkit_account ['email_verified' ]
165
150
account .name = gitkit_account ['name' ]
166
151
account .photo_url = gitkit_account ['photo_url' ]
167
- if not account .email_verified :
168
- if account .email_challenged is None :
169
- send_email_challenge (account )
170
- db .session .flush ()
171
- response = redirect (url_for ('.verify_email' , id = account .id ))
172
- db .session .commit ()
173
- return response
174
152
db .session .flush ()
175
- login_user (account )
153
+ if account .email_verified :
154
+ login_user (account )
155
+ db .session .commit ()
156
+ return render_template ('auth/close-window.html' , message = 'You have signed in.' )
157
+ oob_link = gitkit .get_email_verification_link (email )
158
+ challenge = Challenge (
159
+ oob_code = parse_qs (urlparse (oob_link ).query )['oobCode' ][0 ],
160
+ site_id = site_id ,
161
+ account_id = account .id ,
162
+ moment = datetime .utcnow ())
163
+ db .session .add (challenge )
176
164
db .session .commit ()
177
- return redirect (request .args .get ('next' , request .url_root ))
165
+ text = render_template ('auth/verify-email.txt' , oob_link = oob_link )
166
+ send (email , 'Verify email address' , text )
167
+ return render_template ('auth/close-window.html' , message = 'Email verification link sent.' )
178
168
179
169
180
170
@blueprint .route ('/sign-out' )
@@ -187,15 +177,6 @@ def sign_out():
187
177
return response
188
178
189
179
190
- @blueprint .route ('/account/<id>/verify-email' , methods = {'GET' , 'POST' })
191
- def verify_email (id ):
192
- account = Account .query .get_or_404 (id )
193
- if request .method == 'POST' and not account .email_verified :
194
- send_email_challenge (account )
195
- db .session .commit ()
196
- return render_template ('auth/verify-email.html' , account = account )
197
-
198
-
199
180
@blueprint .route ('/oob-action' )
200
181
def oob_action ():
201
182
result = gitkit .get_oob_result ()
@@ -220,46 +201,30 @@ def oob_action():
220
201
@jsonp
221
202
def site_token (site_id ):
222
203
synchronize (site_id )
223
- if not current_user .is_authenticated :
224
- next = url_for ('.site_authenticated' , site_id = site_id , _external = True )
225
- location = auth_url_for ('widget' , mode = 'select' , next = next , _external = True )
226
- return jsonify ({
227
- 'status_code' : 401 ,
228
- 'location' : location ,
229
- })
230
- for roles in current_user .roles :
231
- if roles .site_id == site_id :
232
- return jsonify ({
233
- 'status_code' : 200 ,
234
- 'access_token' : token_serializer .dumps (current_user .id ),
235
- 'account' : {
236
- 'email' : current_user .email ,
237
- 'name' : current_user .name ,
238
- 'roles' : roles .roles ,
239
- },
240
- 'sign_out' : url_for ('.sign_out' , _external = True ),
241
- })
242
- return jsonify ({
243
- 'status_code' : 403 ,
244
- 'account' : {
245
- 'email' : current_user .email ,
246
- 'name' : current_user .name
247
- },
204
+ next = url_for ('.sign_in_success' , site_id = site_id , _external = True )
205
+ response = {
206
+ 'sign_in' : url_for ('.widget' , mode = 'select' , next = next , _external = True ),
248
207
'sign_out' : url_for ('.sign_out' , _external = True ),
249
- })
250
-
251
-
252
- @blueprint .route ('/site/<site_id>/authenticated' )
253
- def site_authenticated (site_id ):
254
- return render_template ('auth/close-window.html' , message = 'You have signed in.' )
255
-
256
-
257
- def send_email_challenge (account ):
258
- text = render_template (
259
- 'auth/verify-email.txt' ,
260
- oob_link = gitkit .get_email_verification_link (account .email ))
261
- send (account .email , 'Verify email address' , text )
262
- account .email_challenged = datetime .utcnow ()
208
+ }
209
+ user = current_user ._get_current_object ()
210
+ if not user .is_authenticated :
211
+ response ['status_code' ] = 401
212
+ return jsonify (response )
213
+ response ['account' ] = {
214
+ 'email' : user .email ,
215
+ 'email_verified' : user .email_verified ,
216
+ 'name' : user .name ,
217
+ }
218
+ for roles in user .roles :
219
+ if roles .site_id == site_id :
220
+ response ['account' ]['roles' ] = roles .roles
221
+ break
222
+ if not user .email_verified or 'roles' not in response ['account' ]:
223
+ response ['status_code' ] = 403
224
+ return jsonify (response )
225
+ response ['status_code' ] = 200
226
+ response ['access_token' ] = token_serializer .dumps (user .id )
227
+ return jsonify (response )
263
228
264
229
265
230
def send (recipient , subject , text ):
0 commit comments