2013-09-25 20:46:28 +00:00
|
|
|
import logging
|
2013-10-10 03:00:34 +00:00
|
|
|
import requests
|
2013-09-25 20:46:28 +00:00
|
|
|
|
2013-10-14 21:50:07 +00:00
|
|
|
from flask import (abort, redirect, request, url_for, render_template,
|
|
|
|
make_response)
|
|
|
|
from flask.ext.login import login_user, UserMixin, login_required
|
2013-09-27 00:18:36 +00:00
|
|
|
from flask.ext.principal import identity_changed, Identity, AnonymousIdentity
|
2013-09-25 16:45:12 +00:00
|
|
|
|
|
|
|
from data import model
|
2013-10-10 21:32:32 +00:00
|
|
|
from app import app, login_manager, mixpanel
|
2013-10-15 18:48:49 +00:00
|
|
|
from auth.permissions import QuayDeferredPermissionUser
|
2013-09-25 20:46:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
class _LoginWrappedDBUser(UserMixin):
|
2013-10-15 21:49:03 +00:00
|
|
|
def __init__(self, db_username, db_user=None):
|
2013-10-15 18:48:49 +00:00
|
|
|
|
|
|
|
self._db_username = db_username
|
2013-10-15 21:49:03 +00:00
|
|
|
self._db_user = db_user
|
2013-10-15 18:48:49 +00:00
|
|
|
|
|
|
|
def db_user(self):
|
|
|
|
if not self._db_user:
|
|
|
|
self._db_user = model.get_user(self._db_username)
|
|
|
|
return self._db_user
|
|
|
|
|
|
|
|
def is_authenticated(self):
|
|
|
|
return self.db_user() is not None
|
2013-09-25 20:46:28 +00:00
|
|
|
|
|
|
|
def is_active(self):
|
2013-10-15 18:48:49 +00:00
|
|
|
return self.db_user().verified
|
2013-09-25 20:46:28 +00:00
|
|
|
|
|
|
|
def get_id(self):
|
2013-10-15 18:48:49 +00:00
|
|
|
return unicode(self._db_username)
|
2013-09-25 20:46:28 +00:00
|
|
|
|
|
|
|
|
|
|
|
@login_manager.user_loader
|
|
|
|
def load_user(username):
|
2013-10-01 19:43:16 +00:00
|
|
|
logger.debug('Loading user: %s' % username)
|
2013-10-15 18:48:49 +00:00
|
|
|
return _LoginWrappedDBUser(username)
|
2013-09-25 16:45:12 +00:00
|
|
|
|
|
|
|
|
2013-10-10 23:06:04 +00:00
|
|
|
@app.route('/', methods=['GET'], defaults={'path': ''})
|
2013-10-14 02:06:31 +00:00
|
|
|
@app.route('/repository/<path:path>', methods=['GET'])
|
2013-10-10 23:06:04 +00:00
|
|
|
def index(path):
|
2013-10-14 21:50:07 +00:00
|
|
|
return render_template('index.html')
|
2013-09-25 16:45:12 +00:00
|
|
|
|
|
|
|
|
2013-10-14 02:06:31 +00:00
|
|
|
@app.route('/plans/')
|
|
|
|
def plans():
|
|
|
|
return index('')
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/guide/')
|
|
|
|
def guide():
|
|
|
|
return index('')
|
|
|
|
|
|
|
|
|
|
|
|
@app.route('/user/')
|
|
|
|
def user():
|
|
|
|
return index('')
|
|
|
|
|
|
|
|
|
2013-10-14 21:50:07 +00:00
|
|
|
@app.route('/signin/')
|
|
|
|
def signin():
|
|
|
|
return index('')
|
|
|
|
|
|
|
|
|
2013-10-24 21:41:55 +00:00
|
|
|
@app.route('/new/')
|
|
|
|
def new():
|
|
|
|
return index('')
|
|
|
|
|
|
|
|
|
2013-10-16 01:50:14 +00:00
|
|
|
@app.route('/repository/')
|
|
|
|
def repository():
|
|
|
|
return index('')
|
|
|
|
|
2013-10-17 21:45:08 +00:00
|
|
|
@app.route('/v1')
|
|
|
|
@app.route('/v1/')
|
|
|
|
def v1():
|
|
|
|
return index('')
|
2013-10-16 01:50:14 +00:00
|
|
|
|
2013-10-02 18:35:21 +00:00
|
|
|
@app.route('/status', methods=['GET'])
|
|
|
|
def status():
|
|
|
|
return make_response('Healthy')
|
|
|
|
|
|
|
|
|
2013-10-01 21:44:13 +00:00
|
|
|
@app.route('/tos', methods=['GET'])
|
|
|
|
def tos():
|
2013-10-14 21:50:07 +00:00
|
|
|
return render_template('tos.html')
|
2013-10-01 21:44:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
@app.route('/privacy', methods=['GET'])
|
|
|
|
def privacy():
|
2013-10-14 21:50:07 +00:00
|
|
|
return render_template('privacy.html')
|
2013-10-01 21:44:13 +00:00
|
|
|
|
|
|
|
|
2013-09-27 23:55:04 +00:00
|
|
|
def common_login(db_user):
|
2013-10-15 21:49:03 +00:00
|
|
|
if login_user(_LoginWrappedDBUser(db_user.username, db_user)):
|
2013-10-01 19:43:16 +00:00
|
|
|
logger.debug('Successfully signed in as: %s' % db_user.username)
|
2013-10-15 18:48:49 +00:00
|
|
|
new_identity = QuayDeferredPermissionUser(db_user.username, 'username')
|
|
|
|
identity_changed.send(app, identity=new_identity)
|
2013-10-01 19:43:16 +00:00
|
|
|
return True
|
|
|
|
else:
|
2013-10-08 15:29:42 +00:00
|
|
|
logger.debug('User could not be logged in, inactive?.')
|
2013-10-01 19:43:16 +00:00
|
|
|
return False
|
2013-09-27 23:55:04 +00:00
|
|
|
|
|
|
|
|
2013-10-10 03:00:34 +00:00
|
|
|
@app.route('/oauth2/github/callback', methods=['GET'])
|
|
|
|
def github_oauth_callback():
|
|
|
|
code = request.args.get('code')
|
|
|
|
payload = {
|
|
|
|
'client_id': app.config['GITHUB_CLIENT_ID'],
|
|
|
|
'client_secret': app.config['GITHUB_CLIENT_SECRET'],
|
|
|
|
'code': code,
|
|
|
|
}
|
|
|
|
headers = {
|
|
|
|
'Accept': 'application/json'
|
|
|
|
}
|
|
|
|
|
|
|
|
get_access_token = requests.post(app.config['GITHUB_TOKEN_URL'],
|
|
|
|
params=payload, headers=headers)
|
|
|
|
|
|
|
|
token = get_access_token.json()['access_token']
|
|
|
|
|
|
|
|
token_param = {
|
|
|
|
'access_token': token,
|
|
|
|
}
|
|
|
|
get_user = requests.get(app.config['GITHUB_USER_URL'], params=token_param)
|
|
|
|
|
|
|
|
user_data = get_user.json()
|
|
|
|
username = user_data['login']
|
|
|
|
github_id = user_data['id']
|
|
|
|
|
|
|
|
v3_media_type = {
|
|
|
|
'Accept': 'application/vnd.github.v3'
|
|
|
|
}
|
|
|
|
get_email = requests.get(app.config['GITHUB_USER_EMAILS'],
|
|
|
|
params=token_param, headers=v3_media_type)
|
|
|
|
|
|
|
|
# We will accept any email, but we prefer the primary
|
|
|
|
found_email = None
|
|
|
|
for user_email in get_email.json():
|
|
|
|
found_email = user_email['email']
|
|
|
|
if user_email['primary']:
|
|
|
|
break
|
|
|
|
|
|
|
|
to_login = model.verify_federated_login('github', github_id)
|
|
|
|
if not to_login:
|
|
|
|
# try to create the user
|
2013-10-10 16:55:03 +00:00
|
|
|
try:
|
|
|
|
to_login = model.create_federated_user(username, found_email, 'github',
|
|
|
|
github_id)
|
2013-10-15 05:12:23 +00:00
|
|
|
|
|
|
|
# Success, tell mixpanel
|
|
|
|
mixpanel.track(to_login.username, 'register', {'service': 'github'})
|
|
|
|
|
|
|
|
state = request.args.get('state', None)
|
|
|
|
if state:
|
|
|
|
logger.debug('Aliasing with state: %s' % state)
|
|
|
|
mixpanel.alias(to_login.username, state)
|
|
|
|
|
2013-10-10 16:55:03 +00:00
|
|
|
except model.DataModelException, ex:
|
|
|
|
return render_template('githuberror.html', error_message=ex.message)
|
2013-10-10 03:00:34 +00:00
|
|
|
|
|
|
|
if common_login(to_login):
|
|
|
|
return redirect(url_for('index'))
|
|
|
|
|
|
|
|
# TODO something bad happened, we need to tell the user somehow
|
2013-10-10 16:55:03 +00:00
|
|
|
return render_template('githuberror.html')
|
2013-09-25 16:45:12 +00:00
|
|
|
|
|
|
|
|
2013-09-27 23:29:01 +00:00
|
|
|
@app.route('/confirm', methods=['GET'])
|
|
|
|
def confirm_email():
|
2013-09-27 23:55:04 +00:00
|
|
|
code = request.values['code']
|
|
|
|
user = model.confirm_user_email(code)
|
|
|
|
|
|
|
|
common_login(user)
|
|
|
|
|
|
|
|
return redirect(url_for('index'))
|
2013-09-27 23:29:01 +00:00
|
|
|
|
|
|
|
|
2013-10-14 21:50:07 +00:00
|
|
|
@app.route('/recovery', methods=['GET'])
|
|
|
|
def confirm_recovery():
|
|
|
|
code = request.values['code']
|
|
|
|
user = model.validate_reset_code(code)
|
2013-09-27 23:29:01 +00:00
|
|
|
|
2013-10-14 21:50:07 +00:00
|
|
|
if user:
|
|
|
|
common_login(user)
|
|
|
|
return redirect(url_for('user'))
|
|
|
|
else:
|
|
|
|
abort(403)
|
2013-09-27 00:18:36 +00:00
|
|
|
|
|
|
|
|
2013-10-14 21:50:07 +00:00
|
|
|
@app.route('/reset', methods=['GET'])
|
|
|
|
def password_reset():
|
|
|
|
pass
|