1
0
mirror of synced 2024-12-13 23:11:06 +01:00
bemaniutils/bemani/frontend/account/account.py

328 lines
10 KiB
Python

from typing import Dict, Any
from flask import Blueprint, request, redirect, Response, url_for, make_response, render_template
from bemani.common import CardCipher, CardCipherException, AESCipher, Time
from bemani.frontend.app import loginrequired, loginprohibited, success, error, jsonify, valid_email, valid_username, valid_pin, render_react
from bemani.frontend.templates import templates_location
from bemani.frontend.static import static_location
from bemani.frontend.types import g
account_pages = Blueprint(
'account_pages',
__name__,
template_folder=templates_location,
static_folder=static_location,
)
@account_pages.route('/login', methods=['POST'])
@loginprohibited
def login() -> Response:
username = request.form['username']
password = request.form['password']
userid = g.data.local.user.from_username(username)
if userid is None:
error('Unrecognized username or password!')
return Response(render_template('account/login.html', **{'title': 'Log In', 'show_navigation': False, 'username': username}))
if g.data.local.user.validate_password(userid, password):
aes = AESCipher(g.config.secret_key)
sessionID = g.data.local.user.create_session(userid, expiration=90 * 86400)
response = make_response(redirect(url_for('home_pages.viewhome')))
response.set_cookie(
'SessionID',
aes.encrypt(sessionID),
expires=Time.now() + (90 * Time.SECONDS_IN_DAY),
)
return response
else:
error('Unrecognized username or password!')
return Response(render_template('account/login.html', **{'title': 'Log In', 'show_navigation': False, 'username': username}))
@account_pages.route('/login')
@loginprohibited
def viewlogin() -> Response:
return Response(render_template('account/login.html', **{'title': 'Log In', 'show_navigation': False}))
def register_display(card_number: str, username: str, email: str) -> Response:
return Response(render_template(
'account/register.html',
**{
'title': 'Register New Account',
'show_navigation': False,
'card_number': card_number,
'username': username,
'email': email,
},
))
@account_pages.route('/register', methods=['POST'])
@loginprohibited
def register() -> Response:
card_number = request.form['card_number']
pin = request.form['pin']
username = request.form['username']
email = request.form['email']
password1 = request.form['password1']
password2 = request.form['password2']
# First, try to convert the card to a valid E004 ID
try:
cardid = CardCipher.decode(card_number)
except CardCipherException:
error('Invalid card number!')
return register_display(card_number, username, email)
# Now, see if this card ID exists already
userid = g.data.local.user.from_cardid(cardid)
if userid is None:
error('This card has not been used on the network yet!')
return register_display(card_number, username, email)
# Now, make sure this user doesn't already have an account
user = g.data.local.user.get_user(userid)
if user.username is not None or user.email is not None:
error('This card is already in use!')
return register_display(card_number, username, email)
# Now, see if the pin is correct
if not g.data.local.user.validate_pin(userid, pin):
error('The entered PIN does not match the PIN on the card!')
return register_display(card_number, username, email)
# Now, see if the username is valid
if not valid_username(username):
error('Invalid username!')
return register_display(card_number, username, email)
# Now, check whether the username is already in use
if g.data.local.user.from_username(username) is not None:
error('The chosen username is already in use!')
return register_display(card_number, username, email)
# Now, see if the email address is valid
if not valid_email(email):
error('Invalid email address!')
return register_display(card_number, username, email)
# Now, make sure that the passwords match
if password1 != password2:
error('Passwords do not match each other!')
return register_display(card_number, username, email)
# Now, make sure passwords are long enough
if len(password1) < 6:
error('Password is not long enough!')
return register_display(card_number, username, email)
# Now, create the account.
user.username = username
user.email = email
g.data.local.user.put_user(user)
g.data.local.user.update_password(userid, password1)
# Now, log them into that created account!
aes = AESCipher(g.config.secret_key)
sessionID = g.data.local.user.create_session(userid)
success('Successfully registered account!')
response = make_response(redirect(url_for('home_pages.viewhome')))
response.set_cookie('SessionID', aes.encrypt(sessionID))
return response
@account_pages.route('/register')
@loginprohibited
def viewregister() -> Response:
return Response(render_template('account/register.html', **{'title': 'Register New Account', 'show_navigation': False}))
@account_pages.route('/logout')
@loginrequired
def logout() -> Response:
g.data.local.user.destroy_session(g.sessionID)
response = make_response(redirect(url_for('account_pages.viewlogin')))
response.set_cookie('SessionID', '', expires=0)
success('Successfully logged out!')
return response
@account_pages.route('/account')
@loginrequired
def viewaccount() -> Response:
user = g.data.local.user.get_user(g.userID)
return render_react(
'Account Management',
'account/account.react.js',
{
'email': user.email,
'username': user.username,
},
{
'updateemail': url_for('account_pages.updateemail'),
'updatepin': url_for('account_pages.updatepin'),
'updatepassword': url_for('account_pages.updatepassword'),
},
)
@account_pages.route('/account/cards')
@loginrequired
def viewcards() -> Response:
cards = [CardCipher.encode(card) for card in g.data.local.user.get_cards(g.userID)]
return render_react(
'Card Management',
'account/cards.react.js',
{
'cards': cards,
},
{
'addcard': url_for('account_pages.addcard'),
'removecard': url_for('account_pages.removecard'),
'listcards': url_for('account_pages.listcards'),
},
)
@account_pages.route('/account/cards/list')
@jsonify
@loginrequired
def listcards() -> Dict[str, Any]:
# Return new card list
cards = [CardCipher.encode(card) for card in g.data.local.user.get_cards(g.userID)]
return {
'cards': cards,
}
@account_pages.route('/account/cards/add', methods=['POST'])
@jsonify
@loginrequired
def addcard() -> Dict[str, Any]:
# Grab card, convert it
card = request.get_json()['card']
try:
cardid = CardCipher.decode(card)
except CardCipherException:
raise Exception('Invalid card number!')
# See if it is already claimed
userid = g.data.local.user.from_cardid(cardid)
if userid is not None:
raise Exception('This card is already in use!')
# Add it to this user's account
g.data.local.user.add_card(g.userID, cardid)
# Return new card list
cards = [CardCipher.encode(card) for card in g.data.local.user.get_cards(g.userID)]
return {
'cards': cards,
}
@account_pages.route('/account/cards/remove', methods=['POST'])
@jsonify
@loginrequired
def removecard() -> Dict[str, Any]:
# Grab card, convert it
card = request.get_json()['card']
try:
cardid = CardCipher.decode(card)
except CardCipherException:
raise Exception('Invalid card number!')
# Make sure it is our card
userid = g.data.local.user.from_cardid(cardid)
if userid != g.userID:
raise Exception('This card is not yours to delete!')
# Remove it from this user's account
g.data.local.user.destroy_card(g.userID, cardid)
# Return new card list
cards = [CardCipher.encode(card) for card in g.data.local.user.get_cards(g.userID)]
return {
'cards': cards,
}
@account_pages.route('/account/email/update', methods=['POST'])
@jsonify
@loginrequired
def updateemail() -> Dict[str, Any]:
email = request.get_json()['email']
password = request.get_json()['password']
user = g.data.local.user.get_user(g.userID)
if user is None:
raise Exception('Unable to find user to update!')
# Make sure current password matches
if not g.data.local.user.validate_password(g.userID, password):
raise Exception('Current password is not correct!')
if not valid_email(email):
raise Exception('Invalid email address!')
# Update and save
user.email = email
g.data.local.user.put_user(user)
# Return updated email
return {
'email': email,
}
@account_pages.route('/account/pin/update', methods=['POST'])
@jsonify
@loginrequired
def updatepin() -> Dict[str, Any]:
pin = request.get_json()['pin']
user = g.data.local.user.get_user(g.userID)
if user is None:
raise Exception('Unable to find user to update!')
if not valid_pin(pin, 'card'):
raise Exception('Invalid PIN, must be exactly 4 digits!')
# Update and save
g.data.local.user.update_pin(g.userID, pin)
# Return nothing
return {}
@account_pages.route('/account/password/update', methods=['POST'])
@jsonify
@loginrequired
def updatepassword() -> Dict[str, Any]:
old = request.get_json()['old']
new1 = request.get_json()['new1']
new2 = request.get_json()['new2']
user = g.data.local.user.get_user(g.userID)
if user is None:
raise Exception('Unable to find user to update!')
# Make sure current password matches
if not g.data.local.user.validate_password(g.userID, old):
raise Exception('Current password is not correct!')
# Now, make sure that the passwords match
if new1 != new2:
raise Exception('Passwords do not match each other!')
# Now, make sure passwords are long enough
if len(new1) < 6:
raise Exception('Password is not long enough!')
# Update and save
g.data.local.user.update_password(g.userID, new1)
# Return nothing
return {}