mirror of
https://github.com/aljazceru/CTFd.git
synced 2025-12-18 14:34:21 +01:00
Rewrite IP tracking code to only return recent IPs. Move IPs into a modal for admin panel.
This commit is contained in:
6
CTFd/cache/__init__.py
vendored
6
CTFd/cache/__init__.py
vendored
@@ -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):
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
28
CTFd/themes/admin/templates/modals/teams/addresses.html
Normal file
28
CTFd/themes/admin/templates/modals/teams/addresses.html
Normal 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>
|
||||
22
CTFd/themes/admin/templates/modals/users/addresses.html
Normal file
22
CTFd/themes/admin/templates/modals/users/addresses.html
Normal 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>
|
||||
@@ -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">×</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 %}
|
||||
|
||||
@@ -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">×</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 %}
|
||||
|
||||
@@ -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()
|
||||
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():
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user