Skip to content

Commit

Permalink
show ban reason and by which user on player page for admin/mods
Browse files Browse the repository at this point in the history
  • Loading branch information
sbezboro committed Nov 8, 2016
1 parent e6b8634 commit 15826db
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 34 deletions.
1 change: 1 addition & 0 deletions requirements.txt
Expand Up @@ -38,6 +38,7 @@ pyasn1==0.1.7
pycparser==2.10
pycrypto==2.6.1
PyExecJS==1.1.0
pygeoip==0.3.2
pyOpenSSL==0.15.1
PyReact==0.5.2
python-dateutil==2.3
Expand Down
36 changes: 28 additions & 8 deletions standardweb/jobs/query.py
Expand Up @@ -8,12 +8,13 @@

from standardweb import app, celery, db
from standardweb import stats as statsd
from standardweb.lib import api
from standardweb.lib import api, geoip
from standardweb.lib import helpers as h
from standardweb.lib import player as libplayer
from standardweb.lib.constants import *
from standardweb.models import (
Group, PlayerStats, GroupInvite, Player, PlayerActivity, IPTracking,
ServerStatus, MojangStatus, Server
AuditLog, Group, PlayerStats, GroupInvite, Player, PlayerActivity,
IPTracking, ServerStatus, MojangStatus, Server,
)


Expand Down Expand Up @@ -142,13 +143,29 @@ def _query_server(server, mojang_status):

player_stats = []

Player.query.filter(
players_to_sync_ban = Player.query.filter(
Player.uuid.in_(server_status.get('banned_uuids', [])),
Player.banned == False
).update({
'banned': True,
}, synchronize_session=False)

).all()

if players_to_sync_ban:
player_ids_to_sync_ban = [x.id for x in players_to_sync_ban]

Player.query.filter(
Player.id.in_(player_ids_to_sync_ban)
).update({
'banned': True,
}, synchronize_session=False)

for player in players_to_sync_ban:
AuditLog.create(
AuditLog.PLAYER_BAN,
player_id=player.id,
username=player.username,
source='server_sync',
commit=False
)

online_player_ids = []
for player_info in server_status.get('players', []):
username = player_info['username']
Expand Down Expand Up @@ -202,6 +219,9 @@ def _query_server(server, mojang_status):
existing_player_ip = IPTracking(ip=ip, player=player)
existing_player_ip.save(commit=False)

if geoip.is_nok(ip):
libplayer.ban_player(player, with_ip=True, source='query', ip=ip, commit=False)

stats = PlayerStats.query.filter_by(server=server, player=player).first()
if not stats:
stats = PlayerStats(server=server, player=player)
Expand Down
2 changes: 1 addition & 1 deletion standardweb/lib/api.py
Expand Up @@ -87,7 +87,7 @@ def send_stats(server, data):
api_call(server, 'stats', data=data)


def ban_player(player, reason=None, with_ip=False):
def ban_player(player, reason, with_ip):
api_player_action_task.apply_async((
player.uuid,
'ban',
Expand Down
33 changes: 33 additions & 0 deletions standardweb/lib/geoip.py
@@ -0,0 +1,33 @@
import os
import pygeoip

from standardweb import app
from standardweb.lib import cache

PROJECT_PATH = os.path.abspath(os.path.dirname(__name__))
BAD_ORG = 'bad_org'

_orgs = [x.lower() for x in app.config.get('BLACKLIST_IP_ORGS', [])]
_gi4 = pygeoip.GeoIP(
'%s/%s' % (PROJECT_PATH, app.config.get('GEOIP_DB_PATH')),
pygeoip.MEMORY_CACHE
)


@cache.CachedResult('get_ip_org', time=86400)
def get_ip_org(ip):
org = _gi4.org_by_addr(ip)
if org:
return org

return BAD_ORG


def is_nok(ip):
org = get_ip_org(ip)
if org == BAD_ORG:
return False

org = org.lower()

return any(x in org for x in _orgs)
27 changes: 24 additions & 3 deletions standardweb/lib/player.py
Expand Up @@ -4,9 +4,10 @@
from sqlalchemy.sql import func, or_

from standardweb import db
from standardweb.lib import cache
from standardweb.lib import api, cache
from standardweb.lib import helpers as h
from standardweb.models import (
AuditLog,
DeathCount,
KillCount,
MaterialType,
Expand All @@ -15,8 +16,8 @@
PlayerStats,
Server,
Title,
VeteranStatus,
IPTracking)
VeteranStatus
)


def extract_face(image, size):
Expand Down Expand Up @@ -227,3 +228,23 @@ def apply_veteran_titles(player, allow_commit=True):

if update:
player.save(commit=allow_commit)


def ban_player(player, reason=None, with_ip=False, by_user_id=None, source=None, commit=True, **kwargs):
reason = reason or 'The Ban Hammer has spoken!'

api.ban_player(player, reason, with_ip)

AuditLog.create(
AuditLog.PLAYER_BAN,
player_id=player.id,
username=player.username,
by_user_id=by_user_id,
reason=reason,
source=source,
commit=False,
**kwargs
)

player.banned = True
player.save(commit=commit)
19 changes: 17 additions & 2 deletions standardweb/middleware.py
Expand Up @@ -8,9 +8,10 @@
import rollbar

from standardweb import app, stats
from standardweb.lib import csrf
from standardweb.lib import api, csrf, geoip
from standardweb.lib import helpers as h
from standardweb.models import User
from standardweb.lib import player as libplayer
from standardweb.models import User, ForumBan
from standardweb.tasks.access_log import log as log_task
from sqlalchemy.orm import joinedload

Expand Down Expand Up @@ -79,6 +80,20 @@ def track_request_time():
g._start_time = time.time()


@app.before_request
def ensure_valid_user():
if request.method == "POST" and g.user and geoip.is_nok(request.remote_addr):
user = g.user
player = user.player

if not user.forum_ban:
ban = ForumBan(user_id=g.user.id)
ban.save(commit=True)

if player and not player.banned:
libplayer.ban_player(player, source='invalid_user', commit=True)


@app.after_request
def access_log(response):
if not hasattr(g, '_start_time'):
Expand Down
2 changes: 1 addition & 1 deletion standardweb/models.py
Expand Up @@ -862,14 +862,14 @@ class AuditLog(db.Model, Base):
'Player',
backref=backref(
'audit_logs',
order_by='AuditLog.timestamp',
lazy='dynamic'
)
)

PLAYER_TIME_ADJUSTMENT = 'player_time_adjustment'
PLAYER_RENAME = 'player_rename'
PLAYER_BAN = 'player_ban'
QUICK_USER_CREATE = 'quick_user_create'

@classmethod
def create(cls, type, data=None, server_id=None, user_id=None, player_id=None, commit=True, **kw):
Expand Down
13 changes: 13 additions & 0 deletions standardweb/templates/player.html
Expand Up @@ -29,6 +29,19 @@
{% if current_user.admin_or_moderator %}
{% if player.banned %}
Server banned
{% if ban_time %}{{ ban_time|from_now }} {% else %} - date unknown{% endif %}
{% if ban_reason %} for: <b>{{ ban_reason }}</b>{% endif %}
{% if ban_by_user %} | Ban given by: <b>
{% if ban_by_user.player %}
<a href="{{ url_for('player', server_id=server.id, username=ban_by_user.player.username) }}">
{{ ban_by_user.player.username|face_thumb(scaled_size=12) }}
{{ ban_by_user.player.displayname_html|safe }}
</a>
{% else %}
{{ ban_by_user.username }}
{% endif %}</b>
{% endif %}
{% if ban_source %}| Ban source: <b>{{ ban_source }}</b>{% endif %}
{% else %}
<a class="btn btn-lite btn-danger ban" href="#">Server Ban</a>
{% endif %}
Expand Down
12 changes: 10 additions & 2 deletions standardweb/views/api.py
Expand Up @@ -15,6 +15,7 @@
from sqlalchemy.orm import joinedload

from standardweb import app, db, stats
from standardweb.lib import forums as libforums
from standardweb.lib import helpers as h
from standardweb.lib import player as libplayer
from standardweb.lib import realtime
Expand Down Expand Up @@ -225,8 +226,14 @@ def register():
send_creation_email(email, uuid, username)

total_time = libplayer.get_total_player_time(player.id)
if total_time < 5:
if total_time < app.config['MINIMUM_REGISTER_PLAYER_TIME']:
rollbar.report_message('Player creating user account super quickly', level='error', request=request)
AuditLog.create(
AuditLog.QUICK_USER_CREATE,
player_id=player.id,
username=player.username,
commit=True
)

return jsonify({
'err': 0,
Expand Down Expand Up @@ -508,7 +515,8 @@ def get_player_data():
'nickname': player.nickname,
'nickname_ansi': player.nickname_ansi,
'nickname_hmtl': player.nickname_html,
'banned': player.banned
'banned': player.banned,
'can_post': libforums.can_user_post(user)
})


Expand Down
5 changes: 1 addition & 4 deletions standardweb/views/main.py
Expand Up @@ -10,7 +10,7 @@
import StringIO

from standardweb import app
from standardweb.lib import api
from standardweb.lib import forums as libforums
from standardweb.lib import leaderboards as libleaderboards
from standardweb.lib import player as libplayer
from standardweb.lib import server as libserver
Expand Down Expand Up @@ -239,9 +239,6 @@ def chat(server_id=None):
'player': player
}

if player and player.banned:
api.ban_player(player)

status = MojangStatus.query.order_by(MojangStatus.timestamp.desc()).limit(1).first()
if status and not status.session:
flash(
Expand Down
2 changes: 1 addition & 1 deletion standardweb/views/messages.py
Expand Up @@ -2,7 +2,6 @@
import pytz

from flask import (
abort,
g,
jsonify,
render_template,
Expand Down Expand Up @@ -226,6 +225,7 @@ def send_message(username):
body=body,
user_ip=request.remote_addr
)

message.save()

notify_new_message(message)
Expand Down
41 changes: 29 additions & 12 deletions standardweb/views/player.py
Expand Up @@ -2,10 +2,9 @@
from sqlalchemy.orm import joinedload

from standardweb import app
from standardweb.lib import api
from standardweb.lib import helpers as h
from standardweb.lib import player as libplayer
from standardweb.models import AuditLog, IPTracking, Player, Server, User
from standardweb.models import IPTracking, Player, Server, User, AuditLog
from standardweb.views.decorators.auth import login_required
from standardweb.views.decorators.redirect import redirect_route

Expand Down Expand Up @@ -97,6 +96,28 @@ def player(username, server_id=None):
'same_ip_player_list': same_ip_player_list
})

if player.banned:
latest_audit = player.audit_logs.filter(
AuditLog.player == player,
AuditLog.type.in_(['player_ban', 'spam_ban', 'spam_shadow_mute_ban'])
).order_by(
AuditLog.timestamp.desc()
).first()

if latest_audit and latest_audit.data:
retval['ban_time'] = latest_audit.timestamp

if latest_audit.data.get('reason'):
retval['ban_reason'] = latest_audit.data['reason']

if latest_audit.data.get('by_user_id'):
retval['ban_by_user'] = User.query.get(latest_audit.data['by_user_id'])

if latest_audit.data.get('source'):
retval['ban_source'] = latest_audit.data['source']
elif 'spam' in latest_audit.type:
retval['ban_source'] = 'spam'

return render_template(template, **retval)


Expand Down Expand Up @@ -132,19 +153,15 @@ def ban_player(uuid):

reason = request.form.get('reason') or None

api.ban_player(player, reason=reason)

AuditLog.create(
AuditLog.PLAYER_BAN,
player_id=player.id,
by_user_id=g.user.id,
libplayer.ban_player(
player,
reason=reason,
commit=False
with_ip=True,
by_user_id=g.user.id,
source='user_ban_player',
commit=True
)

player.banned = True
player.save(commit=True)

return jsonify({
'err': 0
})

0 comments on commit 15826db

Please sign in to comment.