Rewrite IP tracking code to only return recent IPs. Move IPs into a modal for admin panel.

This commit is contained in:
Kevin Chung
2020-04-30 20:32:26 -04:00
parent 1c10643537
commit 01f2d50a34
11 changed files with 128 additions and 79 deletions

View File

@@ -46,10 +46,10 @@ def clear_pages():
cache.delete_memoized(get_page)
def clear_user_ips(user_id):
from CTFd.utils.user import get_user_ips
def clear_user_recent_ips(user_id):
from CTFd.utils.user import get_user_recent_ips
cache.delete_memoized(get_user_ips, user_id=user_id)
cache.delete_memoized(get_user_recent_ips, user_id=user_id)
def clear_user_session(user_id):

View File

@@ -221,6 +221,10 @@ $(() => {
$("#team-award-modal").modal("toggle");
});
$(".addresses-team").click(function(event) {
$("#team-addresses-modal").modal("toggle");
});
$("#user-award-form").submit(function(e) {
e.preventDefault();
const params = $("#user-award-form").serializeJSON(true);

View File

@@ -419,6 +419,10 @@ $(() => {
$("#user-email-modal").modal("toggle");
});
$(".addresses-user").click(function(event) {
$("#user-addresses-modal").modal("toggle");
});
$("#user-mail-form").submit(emailUser);
$(".delete-submission").click(deleteUserSubmission);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,28 @@
<div class="row">
<div class="col-md-12">
<table class="table table-striped">
<thead>
<tr>
<td class="text-center"><b>User</b></td>
<td class="text-center"><b>IP Address</b></td>
<td class="text-center"><b>Last Seen</b></td>
</tr>
</thead>
<tbody>
{% for addr in addrs %}
<tr>
<td class="text-center">
<a href="{{ url_for("admin.users_detail", user_id=addr.user_id) }}">
{{ addr.user.name }}
</a>
</td>
<td class="text-center">{{ addr.ip }}</td>
<td class="text-center solve-time">
<span data-time="{{ addr.date | isoformat }}"></span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>

View File

@@ -0,0 +1,22 @@
<div class="row">
<div class="col-md-12">
<table class="table table-striped">
<thead>
<tr>
<td class="text-center"><b>IP Address</b></td>
<td class="text-center"><b>Last Seen</b></td>
</tr>
</thead>
<tbody>
{% for addr in addrs %}
<tr>
<td class="text-center">{{ addr.ip }}</td>
<td class="text-center solve-time">
<span data-time="{{ addr.date | isoformat }}"></span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>

View File

@@ -61,6 +61,22 @@
</div>
</div>
<div id="team-addresses-modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-action text-center w-100">IP Addresses</h2>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body clearfix">
{% include "admin/modals/teams/addresses.html" %}
</div>
</div>
</div>
</div>
<div class="jumbotron">
<div class="container">
<h1 id="team-id" class="text-center">{{ team.name }}</h1>
@@ -109,6 +125,7 @@
<small>points</small>
{% endif %}
</h3>
<hr class="w-50">
<div class="pt-3">
<a class="edit-team">
<i class="btn-fa fas fa-pencil-alt fa-2x px-2" data-toggle="tooltip" data-placement="top"
@@ -126,6 +143,11 @@
title="Delete Team"></i>
</a>
</div>
<div class="pt-3">
<a class="addresses-team">
<i class="btn-fa fas fa-network-wired fa-2x px-2" data-toggle="tooltip" data-placement="top" title="IP Addresses"></i>
</a>
</div>
</div>
</div>
@@ -356,37 +378,6 @@
</div>
</div>
</div>
<div class="row pt-5">
<div class="col-md-12">
<table class="table table-striped">
<h3 class="text-center">IP Addresses</h3>
<thead>
<tr>
<td class="text-center"><b>User</b></td>
<td class="text-center"><b>IP Address</b></td>
<td class="text-center"><b>Last Seen</b></td>
</tr>
</thead>
<tbody>
{% for addr in addrs %}
<tr>
<td class="text-center">
<a href="{{ url_for("admin.users_detail", user_id=addr.user_id) }}">
{{ addr.user.name }}
</a>
</td>
<td class="text-center">{{ addr.ip }}</td>
<td class="text-center solve-time">
<span data-time="{{ addr.date | isoformat }}"></span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

View File

@@ -52,6 +52,22 @@
</div>
</div>
<div id="user-addresses-modal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-action text-center w-100">IP Addresses</h2>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body clearfix">
{% include "admin/modals/users/addresses.html" %}
</div>
</div>
</div>
</div>
<div class="jumbotron">
<div class="container">
<h1 id="team-id" class="text-center p-0 m-0">{{ user.name }}</h1>
@@ -112,6 +128,7 @@
<small>points</small>
{% endif %}
</h3>
<hr class="w-50">
<div class="pt-3">
<a class="edit-user">
<i class="btn-fa fas fa-user-edit fa-2x px-2" data-toggle="tooltip" data-placement="top" title="Edit User"></i>
@@ -126,11 +143,16 @@
<i class="btn-fa fas fa-trash-alt fa-2x px-2" data-toggle="tooltip" data-placement="top" title="Delete User"></i>
</a>
</div>
<div class="pt-3">
<a class="addresses-user">
<i class="btn-fa fas fa-network-wired fa-2x px-2" data-toggle="tooltip" data-placement="top" title="IP Addresses"></i>
</a>
</div>
</div>
</div>
<div class="container">
<div class="row">
<div class="row" style="min-height: 300px;">
{% if solves %}
<div id="keys-pie-graph" class="col-md-6">
<div class="text-center">
@@ -167,7 +189,7 @@
aria-controls="nav-missing" aria-selected="false">Missing</a>
</nav>
<div class="tab-content" id="nav-tabContent">
<div class="tab-content" id="nav-tabContent" style="min-height: 300px;">
<div class="tab-pane fade show active" id="nav-solves" role="tabpanel" aria-labelledby="nav-solves-tab">
<div class="row">
<div class="col-md-12">
@@ -335,31 +357,6 @@
</div>
</div>
</div>
<div class="row pt-5">
<div class="col-md-12">
<table class="table table-striped">
<h3 class="text-center">IP Addresses</h3>
<thead>
<tr>
<td class="text-center"><b>IP Address</b></td>
<td class="text-center"><b>Last Seen</b></td>
</tr>
</thead>
<tbody>
{% for addr in addrs %}
<tr>
<td class="text-center">{{ addr.ip }}</td>
<td class="text-center solve-time">
<span data-time="{{ addr.date | isoformat }}"></span>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</div>
{% endblock %}

View File

@@ -7,7 +7,7 @@ from flask import abort, redirect, render_template, request, session, url_for
from sqlalchemy.exc import IntegrityError, InvalidRequestError
from werkzeug.wsgi import DispatcherMiddleware
from CTFd.cache import clear_user_ips
from CTFd.cache import clear_user_recent_ips
from CTFd.exceptions import UserNotFoundException, UserTokenExpiredException
from CTFd.models import Tracking, db
from CTFd.utils import config, get_config, markdown
@@ -42,7 +42,7 @@ from CTFd.utils.security.csrf import generate_nonce
from CTFd.utils.user import (
authed,
get_current_user_attrs,
get_current_user_ips,
get_current_user_recent_ips,
get_current_team_attrs,
get_ip,
is_admin,
@@ -181,18 +181,20 @@ def init_request_processors(app):
return
if authed():
user_ips = get_current_user_ips()
user_ips = get_current_user_recent_ips()
ip = get_ip()
track = None
if ip not in user_ips:
track = Tracking(ip=get_ip(), user_id=session["id"])
db.session.add(track)
else:
if request.method != "GET":
track = Tracking.query.filter_by(
ip=get_ip(), user_id=session["id"]
).first()
if track:
track.date = datetime.datetime.utcnow()
else:
track = Tracking(ip=get_ip(), user_id=session["id"])
db.session.add(track)
if track:
try:
@@ -200,7 +202,7 @@ def init_request_processors(app):
except (InvalidRequestError, IntegrityError):
db.session.rollback()
logout_user()
clear_user_ips(user_id=session["id"])
clear_user_recent_ips(user_id=session["id"])
@app.before_request
def banned():

View File

@@ -120,21 +120,22 @@ def get_ip(req=None):
return remote_addr
def get_current_user_ips():
def get_current_user_recent_ips():
if authed():
return get_user_ips(user_id=session["id"])
return get_user_recent_ips(user_id=session["id"])
else:
return None
@cache.memoize(timeout=60)
def get_user_ips(user_id):
def get_user_recent_ips(user_id):
hour_ago = datetime.datetime.now() - datetime.timedelta(hours=1)
addrs = (
Tracking.query.with_entities(Tracking.ip.distinct())
.filter_by(user_id=user_id)
.filter(Tracking.user_id == user_id, Tracking.date >= hour_ago)
.all()
)
return [ip for ip, in addrs]
return set([ip for (ip,) in addrs])
def get_wrong_submissions_per_minute(account_id):