2
2
import os
3
3
import re
4
4
5
- from datetime import datetime
6
5
from functools import wraps
7
- from urllib .parse import urlparse , parse_qs
8
6
9
- from flask import Blueprint , _request_ctx_stack , abort , jsonify , make_response , \
10
- redirect , render_template , request , url_for
7
+ from flask import Blueprint , jsonify , render_template , url_for
8
+ from flask_firebase import FirebaseAuth
11
9
from flask_login import LoginManager , current_user , login_user , logout_user
12
10
from flask_principal import Identity , Permission , PermissionDenied , Principal
13
- from ..ext .identitytoolkit import Gitkit
14
11
from itsdangerous import URLSafeTimedSerializer
15
12
16
- from ..model import Account , OobAction , Repository , Roles , Site , Sites , db
17
- from .base import app , mailgun , jsonp
13
+ from ..model import Account , Repository , Roles , Site , db
14
+ from .base import app , jsonp
18
15
19
16
20
17
blueprint = Blueprint ('auth' , __name__ )
18
+ firebase = FirebaseAuth (app )
21
19
login_manager = LoginManager (app )
22
20
principal = Principal (app , use_sessions = False , skip_static = True )
23
- if not app .debug :
24
- gitkit = Gitkit (app , {
25
- 'widget' : 'auth.widget' ,
26
- 'sign_in_success' : 'auth.sign_in_success' ,
27
- 'sign_out' : 'auth.sign_out' ,
28
- 'oob_action' : 'auth.oob_action' ,
29
- })
30
- else :
31
- gitkit = None
32
-
33
-
34
- GITKIT_OPTIONS = {'accountChooserEnabled' , 'displayMode' , 'signInOptions' }
35
21
36
22
37
23
token_serializer = URLSafeTimedSerializer (app .secret_key , salt = 'access-token' )
38
24
token_regex = re .compile (r'Bearer\s+([-_.0-9a-zA-Z]+)$' )
39
25
40
26
27
+ @firebase .production_loader
28
+ def production_sign_in (token ):
29
+ account = Account .query .get (token ['sub' ])
30
+ if account is None :
31
+ account = Account .query .filter (Account .email == token ['email' ]).one_or_none ()
32
+ if account is not None :
33
+ # ID Changed when moving from Gitkit to Firebase.
34
+ account .id = token ['sub' ]
35
+ else :
36
+ account = Account (id = token ['sub' ])
37
+ db .session .add (account )
38
+ account .email = token ['email' ]
39
+ account .email_verified = token ['email_verified' ]
40
+ account .name = token ['name' ]
41
+ db .session .flush ()
42
+ login_user (account )
43
+ db .session .commit ()
44
+
45
+
46
+ @firebase .unloader
47
+ def sign_out ():
48
+ logout_user ()
49
+
50
+
41
51
@login_manager .user_loader
42
52
def load_user (id ):
43
53
return Account .query .get (id )
@@ -70,8 +80,9 @@ def authorization_required(*roles):
70
80
def decorator (func ):
71
81
@wraps (func )
72
82
def wrapper (** values ):
73
- if not current_user .email_verified :
74
- abort (403 )
83
+ # XXX
84
+ # if not current_user.email_verified:
85
+ # abort(403)
75
86
site_id = values ['site_id' ]
76
87
synchronize (site_id )
77
88
needs = [(role , site_id ) for role in roles ]
@@ -86,181 +97,52 @@ def permission_denied(exc):
86
97
return 'Forbidden' , 403
87
98
88
99
89
- @blueprint .route ('/widget' , methods = {'GET' , 'POST' })
90
- def widget ():
91
- if app .debug :
92
- if request .method == 'GET' :
93
- return render_template ('auth/widget.html' )
94
- email = request .form ['email' ]
95
- account = Account .query .filter_by (email = email ).one_or_none ()
96
- if account is None :
97
- account = Account (
98
- id = email ,
99
- email = email ,
100
- email_verified = True )
101
- db .session .add (account )
102
- db .session .flush ()
103
- login_user (account )
104
- db .session .commit ()
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
- action = OobAction .query .get (oob_code [0 ])
129
- if action is None :
130
- abort (400 )
131
- base_url = Sites (action .site_id ).get_base_url ()
132
- if not base_url .endswith ('/' ):
133
- base_url += '/'
134
- return redirect ('{}#sign-in' .format (base_url ))
100
+ @blueprint .route ('/signed-in' )
101
+ def signed_in ():
102
+ return render_template ('auth/close-window.html' , message = 'You have signed in.' )
135
103
136
104
137
- @blueprint .route ('/site/<site_id>/sign-in-success' )
138
- def sign_in_success (site_id ):
139
- token = gitkit .verify_token ()
140
- if token is None :
141
- abort (400 )
142
- gitkit_account = gitkit .get_account_by_id (token ['id' ])
143
- account = Account .query .get (token ['id' ])
144
- if account is None :
145
- account = Account (id = token ['id' ])
146
- db .session .add (account )
147
- email = gitkit_account ['email' ]
148
- account .email = email
149
- account .email_verified = gitkit_account ['email_verified' ]
150
- account .name = gitkit_account ['name' ]
151
- account .photo_url = gitkit_account ['photo_url' ]
152
- db .session .flush ()
153
- login_user (account )
154
- if account .email_verified :
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
- action = OobAction (
159
- oob_code = parse_qs (urlparse (oob_link ).query )['oobCode' ][0 ],
160
- site_id = site_id ,
161
- moment = datetime .utcnow ())
162
- db .session .add (action )
163
- db .session .commit ()
164
- text = render_template ('auth/verify-email.txt' , oob_link = oob_link )
165
- send (email , 'Verify email address' , text )
166
- return render_template ('auth/close-window.html' , message = 'Email verification link sent.' )
167
-
168
-
169
- @blueprint .route ('/sign-out' )
170
- def sign_out ():
171
- logout_user ()
172
- text = render_template ('auth/close-window.html' , message = 'You have signed out.' )
173
- response = make_response (text )
174
- if not app .debug :
175
- gitkit .delete_token (response )
176
- return response
177
-
178
-
179
- @blueprint .route ('/oob-action' , methods = {'POST' })
180
- def oob_action ():
181
- url_adapter = _request_ctx_stack .top .url_adapter
182
- url = urlparse (request .referrer )
183
- if url .netloc != request .host :
184
- abort (400 )
185
- endpoint , __ = url_adapter .match (url .path , 'GET' )
186
- if endpoint != 'auth.widget' :
187
- abort (400 )
188
- next = parse_qs (url .query ).get ('next' )
189
- if not next or len (next ) != 1 :
190
- abort (400 )
191
- url = urlparse (next [0 ])
192
- if url .netloc != request .host :
193
- abort (400 )
194
- endpoint , values = url_adapter .match (url .path , 'GET' )
195
- if endpoint != 'auth.sign_in_success' :
196
- abort (400 )
197
- result = gitkit .get_oob_result ()
198
- action = OobAction (
199
- oob_code = parse_qs (urlparse (result ['oob_link' ]).query )['oobCode' ][0 ],
200
- site_id = values ['site_id' ],
201
- moment = datetime .utcnow ())
202
- db .session .add (action )
203
- db .session .commit ()
204
- if result ['action' ] == 'changeEmail' :
205
- text = render_template (
206
- 'auth/change-email.txt' ,
207
- email = result ['email' ],
208
- new_email = result ['new_email' ],
209
- oob_link = result ['oob_link' ])
210
- send (result ['new_email' ], 'Change of email address' , text )
211
- return result ['response_body' ]
212
- if result ['action' ] == 'resetPassword' :
213
- text = render_template (
214
- 'auth/reset-password.txt' ,
215
- oob_link = result ['oob_link' ])
216
- send (result ['email' ], 'Password reset' , text )
217
- return result ['response_body' ]
218
- raise Exception ('Invalid action {}' .format (result ['action' ]))
105
+ @blueprint .route ('/signed-out' )
106
+ def signed_out ():
107
+ return render_template ('auth/close-window.html' , message = 'You have signed out.' )
219
108
220
109
221
110
@blueprint .route ('/site/<site_id>/token' )
222
111
@jsonp
223
112
def site_token (site_id ):
224
113
synchronize (site_id )
225
- next = url_for ('.sign_in_success' , site_id = site_id , _external = True )
226
114
response = {
227
- 'sign_in' : url_for ('.widget' , mode = 'select' , next = next , _external = True ),
228
- 'sign_out' : url_for ('.sign_out' , _external = True ),
115
+ 'sign_in' : firebase .url_for (
116
+ 'widget' ,
117
+ mode = 'select' ,
118
+ next = url_for ('auth.signed_in' , _scheme = 'https' , _external = True ),
119
+ ),
120
+ 'sign_out' : firebase .url_for (
121
+ 'sign_out' ,
122
+ next = url_for ('auth.signed_out' , _scheme = 'https' , _external = True ),
123
+ ),
229
124
}
230
125
user = current_user ._get_current_object ()
231
126
if not user .is_authenticated :
232
127
response ['status_code' ] = 401
233
128
return jsonify (response )
234
- if not user .email_verified :
235
- gitkit_account = gitkit .get_account_by_id (user .id )
236
- user .email_verified = gitkit_account ['email_verified' ]
237
- db .session .commit ()
238
129
response ['account' ] = {
239
130
'email' : user .email ,
240
- 'email_verified' : user .email_verified ,
131
+ 'email_verified' : True , # XXX user.email_verified,
241
132
'name' : user .name ,
242
133
}
243
134
for roles in user .roles :
244
135
if roles .site_id == site_id :
245
136
response ['account' ]['roles' ] = roles .roles
246
137
break
247
- if not user . email_verified or 'roles' not in response ['account' ]:
138
+ if 'roles' not in response ['account' ]: # XXX or not user.email_verified
248
139
response ['status_code' ] = 403
249
140
return jsonify (response )
250
141
response ['status_code' ] = 200
251
142
response ['access_token' ] = token_serializer .dumps (user .id )
252
143
return jsonify (response )
253
144
254
145
255
- def send (recipient , subject , text ):
256
- mailgun .send ({
257
- 'from' : 'no-reply@{}' .format (mailgun .domain ),
258
- 'to' : recipient ,
259
- 'subject' : subject ,
260
- 'text' : text ,
261
- })
262
-
263
-
264
146
def synchronize (site_id ):
265
147
repository = Repository (site_id )
266
148
site = Site .query .get (site_id )
@@ -280,11 +162,6 @@ def synchronize(site_id):
280
162
site = Site (id = site_id )
281
163
db .session .add (site )
282
164
site .mtime = mtime
283
- gitkit_options = data .get ('gitkit_options' ) or None
284
- if gitkit_options is not None :
285
- if not set (gitkit_options ).issubset (GITKIT_OPTIONS ):
286
- raise Exception
287
- site .gitkit_options = gitkit_options
288
165
roles = []
289
166
default_roles = data .get ('default_roles' , ['visitor' ])
290
167
for account in data .get ('accounts' , []):
0 commit comments