This commit is contained in:
Matthew Scragg 2014-08-20 10:28:25 -05:00
parent d0777e2b85
commit b02d3db684
41 changed files with 426 additions and 647 deletions

View file

@ -0,0 +1,18 @@
from wtforms import Form, StringField, PasswordField, validators
class RegistrationForm(Form):
username = StringField('Username', [validators.Length(min=4, max=25)])
email = StringField('Email Address', [validators.Length(min=6, max=35)])
password = PasswordField('Password', [
validators.DataRequired(),
validators.EqualTo('confirm', message='Passwords must match')
])
confirm = PasswordField('Repeat Password')
class LoginForm(Form):
email = StringField('Email', [validators.DataRequired])
password = PasswordField('Password', [validators.DataRequired])

View file

@ -0,0 +1,110 @@
from flask.ext.login import UserMixin, logout_user, login_user
from realms import config, login_manager
from realms.lib.services import db
from itsdangerous import URLSafeSerializer, BadSignature
from hashlib import sha256
import json
import bcrypt
FIELD_MAP = dict(
u='username',
e='email',
p='password',
nv='not_verified',
a='admin',
b='banned')
@login_manager.user_loader
def load_user(user_id):
return User.get(user_id)
@login_manager.token_loader
def load_token(token):
# Load unsafe because payload is needed for sig
sig_okay, payload = URLSafeSerializer(None).load_unsafe(token)
if not payload:
return False
# User key *could* be stored in payload to avoid user lookup in db
user = User.get(payload.get('id'))
if not user:
return False
try:
if User.signer(sha256(user.password).hexdigest()).loads(token):
return user
else:
return False
except BadSignature:
return False
class User(UserMixin):
username = None
email = None
password = None
def __init__(self, email, data=None):
self.id = email
for k, v in data.items():
setattr(self, FIELD_MAP.get(k, k), v)
def get_auth_token(self):
key = sha256(self.password).hexdigest()
return User.signer(key).dumps(dict(id=self.username))
@staticmethod
def create(username, email, password):
User.set(email, dict(u=username, e=email, p=User.hash(password), nv=1))
@staticmethod
def signer(salt):
"""
Signed with app secret salted with sha256 of password hash of user (client secret)
"""
return URLSafeSerializer(config.SECRET + salt)
@staticmethod
def set(email, data):
db.set('u:%s' % email, json.dumps(data, separators=(',', ':')))
@staticmethod
def get(email):
data = db.get('u:%s', email)
try:
data = json.loads(data)
except ValueError:
return None
if data:
return User(email, data)
else:
return None
@staticmethod
def auth(email, password):
user = User.get(email)
if not user:
return False
if bcrypt.checkpw(password, user.password):
login_user(user, remember=True)
return user
else:
return False
@staticmethod
def hash(password):
return bcrypt.hashpw(password, bcrypt.gensalt(log_rounds=12))
@classmethod
def logout(cls):
logout_user()

View file

@ -1,35 +1,36 @@
from flask import render_template, redirect, request, url_for, flash, Blueprint
from realms import redirect_url
from realms.models import User
from flask import g, render_template, request, redirect, Blueprint, flash, url_for
from realms.modules.auth.models import User
from realms.modules.auth.forms import LoginForm, RegistrationForm
from realms import config
blueprint = Blueprint('auth', __name__)
blueprint = Blueprint('auth', __name__, url_prefix=config.RELATIVE_PATH)
@blueprint.route("/logout/")
def logout():
@blueprint.route("/logout")
def logout_page():
User.logout()
return redirect(url_for('root'))
flash("You are now logged out")
return redirect(url_for(config.ROOT_ENDPOINT))
@blueprint.route("/register/", methods=['GET', 'POST'])
def register():
if request.method == 'POST':
if User.register(request.form.get('username'), request.form.get('email'), request.form.get('password')):
return redirect(url_for('root'))
else:
# Login failed
return redirect(url_for('.register'))
else:
return render_template('auth/register.html')
@blueprint.route("/login/", methods=['GET', 'POST'])
@blueprint.route("/login")
def login():
if request.method == 'POST':
if request.method == "POST":
form = RegistrationForm()
# TODO
if not form.validate():
flash('Form invalid')
return redirect(url_for('auth.login'))
if User.auth(request.form['email'], request.form['password']):
return redirect(redirect_url(referrer=url_for('root')))
else:
flash("Email or Password invalid")
return redirect(url_for(".login"))
return redirect(request.args.get("next") or url_for(config.ROOT_ENDPOINT))
return render_template("auth/login.html")
@blueprint.route("/register")
def register():
if request.method == "POST":
return redirect(request.args.get("next") or url_for(config.ROOT_ENDPOINT))
else:
return render_template('auth/login.html')
return render_template("auth/register.html")