2023-08-05 21:25:18 +12:00
|
|
|
from datetime import date, datetime, timedelta
|
2023-12-30 19:03:44 +13:00
|
|
|
from flask import redirect, url_for, flash, request, make_response, session, Markup, current_app, g
|
2023-08-05 21:25:18 +12:00
|
|
|
from werkzeug.urls import url_parse
|
|
|
|
from flask_login import login_user, logout_user, current_user
|
|
|
|
from flask_babel import _
|
2023-12-31 12:09:20 +13:00
|
|
|
from app import db, cache
|
2023-08-05 21:25:18 +12:00
|
|
|
from app.auth import bp
|
|
|
|
from app.auth.forms import LoginForm, RegistrationForm, ResetPasswordRequestForm, ResetPasswordForm
|
2023-08-26 15:41:11 +12:00
|
|
|
from app.auth.util import random_token
|
2023-12-30 19:03:44 +13:00
|
|
|
from app.models import User, utcnow, IpBan
|
2023-08-26 15:41:11 +12:00
|
|
|
from app.auth.email import send_password_reset_email, send_welcome_email, send_verification_email
|
2023-08-29 22:01:06 +12:00
|
|
|
from app.activitypub.signature import RsaKeys
|
2023-12-31 12:09:20 +13:00
|
|
|
from app.utils import render_template, ip_address, user_ip_banned, user_cookie_banned, banned_ip_addresses
|
2023-08-05 21:25:18 +12:00
|
|
|
|
|
|
|
|
|
|
|
@bp.route('/login', methods=['GET', 'POST'])
|
|
|
|
def login():
|
|
|
|
if current_user.is_authenticated:
|
|
|
|
next_page = request.args.get('next')
|
|
|
|
if not next_page or url_parse(next_page).netloc != '':
|
|
|
|
next_page = url_for('main.index')
|
|
|
|
return redirect(next_page)
|
|
|
|
form = LoginForm()
|
|
|
|
if form.validate_on_submit():
|
2023-11-22 20:48:27 +13:00
|
|
|
user = User.query.filter_by(user_name=form.user_name.data, ap_id=None).first()
|
2023-08-05 21:25:18 +12:00
|
|
|
if user is None:
|
2023-12-29 17:32:35 +13:00
|
|
|
flash(_('No account exists with that user name.'), 'error')
|
|
|
|
return redirect(url_for('auth.login'))
|
|
|
|
if user.deleted:
|
|
|
|
flash(_('No account exists with that user name.'), 'error')
|
2023-08-05 21:25:18 +12:00
|
|
|
return redirect(url_for('auth.login'))
|
|
|
|
if not user.check_password(form.password.data):
|
|
|
|
if user.password_hash is None:
|
|
|
|
if "@gmail.com" in user.email:
|
|
|
|
message = Markup(_('Invalid password. Please click the "Login using Google" button or <a href="/auth/reset_password_request">reset your password</a>.'))
|
|
|
|
flash(message, 'warning')
|
|
|
|
else:
|
|
|
|
message = Markup(_('Invalid password. Please <a href="/auth/reset_password_request">reset your password</a>.'))
|
|
|
|
flash(message, 'error')
|
|
|
|
return redirect(url_for('auth.login'))
|
|
|
|
flash(_('Invalid password'))
|
|
|
|
return redirect(url_for('auth.login'))
|
2023-12-30 19:03:44 +13:00
|
|
|
if user.banned or user_ip_banned() or user_cookie_banned():
|
|
|
|
flash(_('You have been banned.'), 'error')
|
|
|
|
|
|
|
|
response = make_response(redirect(url_for('auth.login')))
|
|
|
|
# Detect if a banned user tried to log in from a new IP address
|
|
|
|
if user.banned and not user_ip_banned():
|
|
|
|
# If so, ban their new IP address as well
|
|
|
|
new_ip_ban = IpBan(ip_address=ip_address(), notes=user.user_name + ' used new IP address')
|
|
|
|
db.session.add(new_ip_ban)
|
|
|
|
db.session.commit()
|
2024-01-04 17:07:02 +13:00
|
|
|
cache.delete_memoized(banned_ip_addresses)
|
2023-12-30 19:03:44 +13:00
|
|
|
|
|
|
|
# Set a cookie so we have another way to track banned people
|
|
|
|
response.set_cookie('sesion', '17489047567495', expires=datetime(year=2099, month=12, day=30))
|
|
|
|
return response
|
2023-08-05 21:25:18 +12:00
|
|
|
login_user(user, remember=True)
|
2023-12-12 08:53:35 +13:00
|
|
|
current_user.last_seen = utcnow()
|
2023-12-30 19:03:44 +13:00
|
|
|
current_user.ip_address = ip_address()
|
2023-08-05 21:25:18 +12:00
|
|
|
db.session.commit()
|
|
|
|
next_page = request.args.get('next')
|
|
|
|
if not next_page or url_parse(next_page).netloc != '':
|
|
|
|
next_page = url_for('main.index')
|
2024-01-08 19:41:32 +13:00
|
|
|
response = make_response(redirect(next_page))
|
|
|
|
if form.low_bandwidth_mode.data:
|
|
|
|
response.set_cookie('low_bandwidth', '1', expires=datetime(year=2099, month=12, day=30))
|
|
|
|
else:
|
|
|
|
response.set_cookie('low_bandwidth', '0', expires=datetime(year=2099, month=12, day=30))
|
|
|
|
return response
|
2023-08-05 21:25:18 +12:00
|
|
|
return render_template('auth/login.html', title=_('Login'), form=form)
|
|
|
|
|
|
|
|
|
|
|
|
@bp.route('/logout')
|
|
|
|
def logout():
|
|
|
|
logout_user()
|
2024-01-08 19:41:32 +13:00
|
|
|
response = make_response(redirect(url_for('main.index')))
|
|
|
|
response.set_cookie('low_bandwidth', '0', expires=datetime(year=2099, month=12, day=30))
|
|
|
|
return response
|
2023-08-05 21:25:18 +12:00
|
|
|
|
|
|
|
|
|
|
|
@bp.route('/register', methods=['GET', 'POST'])
|
|
|
|
def register():
|
2023-12-30 19:22:22 +13:00
|
|
|
disallowed_usernames = ['admin']
|
2023-08-05 21:25:18 +12:00
|
|
|
if current_user.is_authenticated:
|
|
|
|
return redirect(url_for('main.index'))
|
|
|
|
form = RegistrationForm()
|
|
|
|
if form.validate_on_submit():
|
|
|
|
if form.email.data == '': # ignore any registration where the email field is filled out. spam prevention
|
|
|
|
if form.real_email.data.lower().startswith('postmaster@') or form.real_email.data.lower().startswith('abuse@') or \
|
|
|
|
form.real_email.data.lower().startswith('noc@'):
|
|
|
|
flash(_('Sorry, you cannot use that email address'), 'error')
|
2023-12-30 19:22:22 +13:00
|
|
|
if form.user_name.data in disallowed_usernames:
|
|
|
|
flash(_('Sorry, you cannot use that user name'), 'error')
|
2023-08-05 21:25:18 +12:00
|
|
|
else:
|
2023-08-26 15:41:11 +12:00
|
|
|
verification_token = random_token(16)
|
2023-11-26 23:21:04 +13:00
|
|
|
form.user_name.data = form.user_name.data.strip()
|
2024-01-01 14:49:15 +13:00
|
|
|
user = User(user_name=form.user_name.data, title=form.user_name.data, email=form.real_email.data,
|
2024-01-04 16:00:19 +13:00
|
|
|
verification_token=verification_token, instance_id=1, ip_address=ip_address(),
|
2023-12-30 19:03:44 +13:00
|
|
|
banned=user_ip_banned() or user_cookie_banned())
|
2023-08-05 21:25:18 +12:00
|
|
|
user.set_password(form.password.data)
|
2023-08-26 15:41:11 +12:00
|
|
|
db.session.add(user)
|
2023-08-05 21:25:18 +12:00
|
|
|
db.session.commit()
|
|
|
|
login_user(user, remember=True)
|
|
|
|
send_welcome_email(user)
|
2023-08-26 15:41:11 +12:00
|
|
|
send_verification_email(user)
|
|
|
|
|
|
|
|
if current_app.config['MODE'] == 'development':
|
|
|
|
current_app.logger.info('Verify account:' + url_for('auth.verify_email', token=user.verification_token, _external=True))
|
2023-08-05 21:25:18 +12:00
|
|
|
|
2024-01-05 14:09:46 +13:00
|
|
|
flash(_('Great, you are now a registered user! Choose some communities to join. Use the topic filter to narrow things down.'))
|
2023-08-05 21:25:18 +12:00
|
|
|
|
2024-01-04 16:00:19 +13:00
|
|
|
resp = make_response(redirect(url_for('main.list_communities')))
|
2023-12-30 19:03:44 +13:00
|
|
|
if user_ip_banned():
|
|
|
|
resp.set_cookie('sesion', '17489047567495', expires=datetime(year=2099, month=12, day=30))
|
2023-08-05 21:25:18 +12:00
|
|
|
return resp
|
2023-12-30 19:03:44 +13:00
|
|
|
return render_template('auth/register.html', title=_('Register'), form=form, site=g.site)
|
2023-08-05 21:25:18 +12:00
|
|
|
|
|
|
|
|
|
|
|
@bp.route('/reset_password_request', methods=['GET', 'POST'])
|
|
|
|
def reset_password_request():
|
|
|
|
if current_user.is_authenticated:
|
|
|
|
return redirect(url_for('main.index'))
|
|
|
|
form = ResetPasswordRequestForm()
|
|
|
|
if form.validate_on_submit():
|
|
|
|
if form.email.data.lower().startswith('postmaster@') or form.email.data.lower().startswith('abuse@') or \
|
|
|
|
form.email.data.lower().startswith('noc@'):
|
2024-01-06 15:30:50 +13:00
|
|
|
flash(_('Sorry, you cannot use that email address.'), 'error')
|
2023-08-05 21:25:18 +12:00
|
|
|
else:
|
|
|
|
user = User.query.filter_by(email=form.email.data).first()
|
|
|
|
if user:
|
|
|
|
send_password_reset_email(user)
|
2024-01-06 15:30:50 +13:00
|
|
|
flash(_('Check your email for a link to reset your password.'))
|
2023-08-05 21:25:18 +12:00
|
|
|
return redirect(url_for('auth.login'))
|
|
|
|
else:
|
|
|
|
flash(_('No account with that email address exists'), 'warning')
|
|
|
|
return render_template('auth/reset_password_request.html',
|
|
|
|
title=_('Reset Password'), form=form)
|
|
|
|
|
|
|
|
|
|
|
|
@bp.route('/reset_password/<token>', methods=['GET', 'POST'])
|
|
|
|
def reset_password(token):
|
|
|
|
if current_user.is_authenticated:
|
|
|
|
return redirect(url_for('main.index'))
|
|
|
|
user = User.verify_reset_password_token(token)
|
|
|
|
if not user:
|
|
|
|
return redirect(url_for('main.index'))
|
|
|
|
form = ResetPasswordForm()
|
|
|
|
if form.validate_on_submit():
|
|
|
|
user.set_password(form.password.data)
|
|
|
|
db.session.commit()
|
2024-01-06 15:30:50 +13:00
|
|
|
flash(_('Your password has been reset. Please use it to log in with user name of %(name)s.', name=user.user_name))
|
2023-08-05 21:25:18 +12:00
|
|
|
return redirect(url_for('auth.login'))
|
2023-08-26 15:41:11 +12:00
|
|
|
return render_template('auth/reset_password.html', form=form)
|
|
|
|
|
|
|
|
|
|
|
|
@bp.route('/verify_email/<token>')
|
|
|
|
def verify_email(token):
|
|
|
|
if token != '':
|
|
|
|
user = User.query.filter_by(verification_token=token).first()
|
|
|
|
if user is not None:
|
2023-10-23 13:03:35 +13:00
|
|
|
if user.banned:
|
|
|
|
flash('You have been banned.', 'error')
|
|
|
|
return redirect(url_for('main.index'))
|
2023-08-29 22:01:06 +12:00
|
|
|
if user.verified: # guard against users double-clicking the link in the email
|
|
|
|
return redirect(url_for('main.index'))
|
2023-08-26 15:41:11 +12:00
|
|
|
user.verified = True
|
2023-12-12 08:53:35 +13:00
|
|
|
user.last_seen = utcnow()
|
2023-08-29 22:01:06 +12:00
|
|
|
private_key, public_key = RsaKeys.generate_keypair()
|
|
|
|
user.private_key = private_key
|
|
|
|
user.public_key = public_key
|
2023-11-26 23:21:04 +13:00
|
|
|
user.ap_profile_id = f"https://{current_app.config['SERVER_NAME']}/u/{user.user_name}"
|
|
|
|
user.ap_public_url = f"https://{current_app.config['SERVER_NAME']}/u/{user.user_name}"
|
|
|
|
user.ap_inbox_url = f"https://{current_app.config['SERVER_NAME']}/u/{user.user_name}/inbox"
|
2023-08-26 15:41:11 +12:00
|
|
|
db.session.commit()
|
2023-11-26 23:21:04 +13:00
|
|
|
flash(_('Thank you for verifying your email address.'))
|
2023-08-26 15:41:11 +12:00
|
|
|
else:
|
|
|
|
flash(_('Email address validation failed.'), 'error')
|
2023-10-23 13:03:35 +13:00
|
|
|
return redirect(url_for('main.index'))
|
|
|
|
|
|
|
|
|
|
|
|
@bp.route('/validation_required')
|
|
|
|
def validation_required():
|
|
|
|
return render_template('auth/validation_required.html')
|
2023-12-17 00:12:49 +13:00
|
|
|
|
|
|
|
|
|
|
|
@bp.route('/permission_denied')
|
|
|
|
def permission_denied():
|
|
|
|
return render_template('auth/permission_denied.html')
|