Better bans (#341)

* better bans

* put jinja2 template into correct file
This commit is contained in:
A nyaa developer
2017-08-26 00:53:35 +02:00
committed by Arylide
parent 6aab5557d6
commit f8a314df4f
16 changed files with 609 additions and 65 deletions

View File

@@ -28,12 +28,16 @@ def login():
if not user:
user = models.User.by_email(username)
if (not user or password != user.password_hash or
user.status == models.UserStatusType.INACTIVE):
if not user or password != user.password_hash:
flask.flash(flask.Markup(
'<strong>Login failed!</strong> Incorrect username or password.'), 'danger')
return flask.redirect(flask.url_for('account.login'))
if user.status != models.UserStatusType.ACTIVE:
flask.flash(flask.Markup(
'<strong>Login failed!</strong> Account is not activated or banned.'), 'danger')
return flask.redirect(flask.url_for('account.login'))
user.last_login_date = datetime.utcnow()
user.last_login_ip = ip_address(flask.request.remote_addr).packed
db.session.add(user)

View File

@@ -1,3 +1,5 @@
from ipaddress import ip_address
import flask
from nyaa import forms, models
@@ -20,6 +22,45 @@ def view_adminlog():
adminlog=logs)
@bp.route('/bans', endpoint='bans', methods=['GET', 'POST'])
def view_adminbans():
if not flask.g.user or not flask.g.user.is_moderator:
flask.abort(403)
form = forms.StringSubmitForm()
if flask.request.method == 'POST' and form.validate():
ban = models.Ban.by_id(form.submit.data)
if not ban:
flask.abort(404)
log = 'Unbanned ban #{0}'.format(ban.id)
if ban.user:
log += ' ' + ban.user.username
ban.user.status = models.UserStatusType.ACTIVE
db.session.add(ban.user)
if ban.user_ip:
log += ' IP({0})'.format(ip_address(ban.user_ip))
adminlog = models.AdminLog(log=log, admin_id=flask.g.user.id)
db.session.add(adminlog)
db.session.delete(ban)
db.session.commit()
flask.flash('Unbanned ban #{0}'.format(ban.id), 'success')
page = flask.request.args.get('p', flask.request.args.get('offset', 1, int), int)
bans = models.Ban.all_bans() \
.order_by(models.Ban.created_time.desc()) \
.paginate(page=page, per_page=20)
return flask.render_template('admin_bans.html',
bans=bans,
form=form)
@bp.route('/reports', endpoint='reports', methods=['GET', 'POST'])
def view_reports():
if not flask.g.user or not flask.g.user.is_moderator:
@@ -40,7 +81,7 @@ def view_reports():
if not torrent or not report or report.status != 0:
flask.abort(404)
else:
log = "Report #{}: {} [#{}]({}), reported by [{}]({})"
log = 'Report #{}: {} [#{}]({}), reported by [{}]({})'
if action == 'delete':
torrent.deleted = True
report.status = 1

View File

@@ -1,6 +1,7 @@
import math
import re
from datetime import datetime, timedelta
from ipaddress import ip_address
import flask
from flask_paginate import Pagination
@@ -28,6 +29,10 @@ def before_request():
if not user:
return logout()
# Logout inactive and banned users
if user.status != models.UserStatusType.ACTIVE:
return logout()
flask.g.user = user
if 'timeout' not in flask.session or flask.session['timeout'] < datetime.now():
@@ -35,7 +40,14 @@ def before_request():
flask.session.permanent = True
flask.session.modified = True
if flask.g.user.status == models.UserStatusType.BANNED:
# Check if user is banned on POST
if flask.request.method == 'POST':
ip = ip_address(flask.request.remote_addr).packed
banned = models.Ban.banned(None, ip).first()
if banned:
if flask.g.user:
return logout()
return 'You are banned.', 403

View File

@@ -1,5 +1,6 @@
import json
import os.path
from ipaddress import ip_address
from urllib.parse import quote
import flask
@@ -80,8 +81,9 @@ def view_torrent(torrent_id):
def edit_torrent(torrent_id):
torrent = models.Torrent.by_id(torrent_id)
form = forms.EditForm(flask.request.form)
delete_form = forms.DeleteForm()
form.category.choices = _create_upload_category_choices()
delete_form = forms.DeleteForm()
ban_form = None
editor = flask.g.user
@@ -96,7 +98,10 @@ def edit_torrent(torrent_id):
if not editor or not (editor is torrent.user or editor.is_moderator):
flask.abort(403)
if flask.request.method == 'POST' and form.validate():
if editor and editor.is_moderator and editor.level > torrent.user.level:
ban_form = forms.BanForm()
if flask.request.method == 'POST' and form.submit.data and form.validate():
# Form has been sent, edit torrent with data.
torrent.main_category_id, torrent.sub_category_id = \
form.category.parsed_data.get_category_ids()
@@ -127,9 +132,12 @@ def edit_torrent(torrent_id):
flask.flash(flask.Markup(
'Torrent has been successfully edited! Changes might take a few minutes to show up.'),
'info')
'success')
return flask.redirect(url)
elif flask.request.method == 'POST' and delete_form.validate() and \
(not ban_form or ban_form.validate()):
return _delete_torrent(torrent, delete_form, ban_form)
else:
if flask.request.method != 'POST':
# Fill form data only if the POST didn't fail
@@ -146,39 +154,43 @@ def edit_torrent(torrent_id):
form.is_trusted.data = torrent.trusted
form.is_deleted.data = torrent.deleted
ipbanned = None
if editor.is_moderator:
tbanned = models.Ban.banned(None, torrent.uploader_ip).first()
ubanned = True
if torrent.user:
ubanned = models.Ban.banned(None, torrent.user.last_login_ip).first()
ipbanned = (tbanned and ubanned)
return flask.render_template('edit.html',
form=form,
delete_form=delete_form,
torrent=torrent)
ban_form=ban_form,
torrent=torrent,
ipbanned=ipbanned)
@bp.route('/view/<int:torrent_id>/delete', endpoint='delete', methods=['POST'])
def delete_torrent(torrent_id):
torrent = models.Torrent.by_id(torrent_id)
form = forms.DeleteForm(flask.request.form)
def _delete_torrent(torrent, form, banform):
editor = flask.g.user
if not torrent:
flask.abort(404)
uploader = torrent.user
# Only allow admins edit deleted torrents
if torrent.deleted and not (editor and editor.is_moderator):
flask.abort(404)
# Only allow torrent owners or admins edit torrents
if not editor or not (editor is torrent.user or editor.is_moderator):
flask.abort(403)
action = None
url = flask.url_for('main.home')
ban_torrent = form.ban.data
if banform:
ban_torrent = ban_torrent or banform.ban_user.data or banform.ban_userip.data
if form.delete.data and not torrent.deleted:
action = 'deleted'
torrent.deleted = True
db.session.add(torrent)
elif form.ban.data and not torrent.banned and editor.is_moderator:
elif ban_torrent and not torrent.banned and editor.is_moderator:
action = 'banned'
torrent.banned = True
if not torrent.deleted:
@@ -202,20 +214,80 @@ def delete_torrent(torrent_id):
backend.tracker_api([torrent.info_hash], 'unban')
db.session.add(torrent)
if not action:
if not action and not ban_torrent:
flask.flash(flask.Markup('What the fuck are you doing?'), 'danger')
return flask.redirect(flask.url_for('torrents.edit', torrent_id=torrent.id))
if editor.is_moderator:
if action and editor.is_moderator:
url = flask.url_for('torrents.view', torrent_id=torrent.id)
if editor is not torrent.user:
if editor is not uploader:
log = "Torrent [#{0}]({1}) has been {2}".format(torrent.id, url, action)
adminlog = models.AdminLog(log=log, admin_id=editor.id)
db.session.add(adminlog)
if action:
db.session.commit()
flask.flash(flask.Markup('Torrent has been successfully {0}.'.format(action)), 'success')
if not banform or not (banform.ban_user.data or banform.ban_userip.data):
return flask.redirect(url)
if banform.ban_userip.data:
tbanned = models.Ban.banned(None, torrent.uploader_ip).first()
ubanned = True
if uploader:
ubanned = models.Ban.banned(None, uploader.last_login_ip).first()
ipbanned = (tbanned and ubanned)
if (banform.ban_user.data and (not uploader or uploader.is_banned)) or \
(banform.ban_userip.data and ipbanned):
flask.flash(flask.Markup('What the fuck are you doing?'), 'danger')
return flask.redirect(flask.url_for('torrents.edit', torrent_id=torrent.id))
flavor = "Nyaa" if app.config['SITE_FLAVOR'] == 'nyaa' else "Sukebei"
eurl = flask.url_for('torrents.view', torrent_id=torrent.id, _external=True)
reason = "[{0}#{1}]({2}) {3}".format(flavor, torrent.id, eurl, banform.reason.data)
ban1 = models.Ban(admin_id=editor.id, reason=reason)
ban2 = models.Ban(admin_id=editor.id, reason=reason)
db.session.add(ban1)
if uploader:
uploader.status = models.UserStatusType.BANNED
db.session.add(uploader)
ban1.user_id = uploader.id
ban2.user_id = uploader.id
if banform.ban_userip.data:
if not ubanned:
ban1.user_ip = ip_address(uploader.last_login_ip)
if not tbanned:
uploader_ip = ip_address(torrent.uploader_ip)
if ban1.user_ip != uploader_ip:
ban2.user_ip = uploader_ip
db.session.add(ban2)
else:
ban1.user_ip = ip_address(torrent.uploader_ip)
uploader_str = "Anonymous"
if uploader:
uploader_url = flask.url_for('users.view_user', user_name=uploader.username)
uploader_str = "[{0}]({1})".format(uploader.username, uploader_url)
if ban1.user_ip:
uploader_str += " IP({0})".format(ban1.user_ip)
ban1.user_ip = ban1.user_ip.packed
if ban2.user_ip:
uploader_str += " IP({0})".format(ban2.user_ip)
ban2.user_ip = ban2.user_ip.packed
log = "Uploader {0} of torrent [#{1}]({2}) has been banned.".format(
uploader_str, torrent.id, flask.url_for('torrents.view', torrent_id=torrent.id), action)
adminlog = models.AdminLog(log=log, admin_id=editor.id)
db.session.add(adminlog)
db.session.commit()
flask.flash(flask.Markup('Torrent has been successfully {0}.'.format(action)), 'info')
flask.flash(flask.Markup('Uploader has been successfully banned.'), 'success')
return flask.redirect(url)

View File

@@ -1,4 +1,5 @@
import math
from ipaddress import ip_address
import flask
from flask_paginate import Pagination
@@ -23,14 +24,23 @@ def view_user(user_name):
flask.abort(404)
admin_form = None
ban_form = None
bans = None
ipbanned = None
if flask.g.user and flask.g.user.is_moderator and flask.g.user.level > user.level:
admin_form = forms.UserForm()
default, admin_form.user_class.choices = _create_user_class_choices(user)
if flask.request.method == 'GET':
admin_form.user_class.data = default
ban_form = forms.BanForm()
if flask.request.method == 'POST':
doban = (ban_form.ban_user.data or ban_form.unban.data or ban_form.ban_userip.data)
bans = models.Ban.banned(user.id, user.last_login_ip).all()
ipbanned = list(filter(lambda b: b.user_ip == user.last_login_ip, bans))
url = flask.url_for('users.view_user', user_name=user.username)
if flask.request.method == 'POST' and admin_form and admin_form.validate():
if flask.request.method == 'POST' and admin_form and not doban and admin_form.validate():
selection = admin_form.user_class.data
log = None
if selection == 'regular':
@@ -42,9 +52,6 @@ def view_user(user_name):
elif selection == 'moderator':
user.level = models.UserLevelType.MODERATOR
log = "[{}]({}) changed to moderator user".format(user_name, url)
elif selection == 'banned':
user.status = models.UserStatusType.BANNED
log = "[{}]({}) changed to banned user".format(user_name, url)
adminlog = models.AdminLog(log=log, admin_id=flask.g.user.id)
db.session.add(user)
@@ -53,6 +60,46 @@ def view_user(user_name):
return flask.redirect(url)
if flask.request.method == 'POST' and ban_form and doban and ban_form.validate():
if (ban_form.ban_user.data and user.is_banned) or \
(ban_form.ban_userip.data and ipbanned) or \
(ban_form.unban.data and not user.is_banned and not bans):
flask.flash(flask.Markup('What the fuck are you doing?'), 'danger')
return flask.redirect(url)
user_str = "[{0}]({1})".format(user.username, url)
if ban_form.unban.data:
action = "unbanned"
user.status = models.UserStatusType.ACTIVE
db.session.add(user)
for ban in bans:
if ban.user_ip:
user_str += " IP({0})".format(ip_address(ban.user_ip))
db.session.delete(ban)
else:
action = "banned"
user.status = models.UserStatusType.BANNED
db.session.add(user)
ban = models.Ban(admin_id=flask.g.user.id, user_id=user.id, reason=ban_form.reason.data)
db.session.add(ban)
if ban_form.ban_userip.data:
ban.user_ip = ip_address(user.last_login_ip)
user_str += " IP({0})".format(ban.user_ip)
ban.user_ip = ban.user_ip.packed
log = "User {0} has been {1}.".format(user_str, action)
adminlog = models.AdminLog(log=log, admin_id=flask.g.user.id)
db.session.add(adminlog)
db.session.commit()
flask.flash(flask.Markup('User has been successfully {0}.'.format(action)), 'success')
return flask.redirect(url)
req_args = flask.request.args
search_term = chain_get(req_args, 'q', 'term')
@@ -117,7 +164,10 @@ def view_user(user_name):
user=user,
user_page=True,
rss_filter=rss_query_string,
admin_form=admin_form)
admin_form=admin_form,
ban_form=ban_form,
bans=bans,
ipbanned=ipbanned)
# Similar logic as home page
else:
if use_elastic:
@@ -132,7 +182,10 @@ def view_user(user_name):
user=user,
user_page=True,
rss_filter=rss_query_string,
admin_form=admin_form)
admin_form=admin_form,
ban_form=ban_form,
bans=bans,
ipbanned=ipbanned)
@bp.route('/user/activate/<payload>')
@@ -164,8 +217,6 @@ def _create_user_class_choices(user):
choices.append(('trusted', 'Trusted'))
if flask.g.user.is_superadmin:
choices.append(('moderator', 'Moderator'))
if flask.g.user.is_moderator:
choices.append(('banned', 'Banned'))
if user:
if user.is_moderator: