mirror of
https://github.com/aljazceru/CTFd.git
synced 2026-02-01 20:34:36 +01:00
Lookup the respective country for IP addresses in the admin panel (#1512)
* Adds support for looking up countries by IP address. * Shows country and flag for a user/team's IP addresses in the admin panel * Adds support for `GEOIP_DATABASE_PATH` in config.py * Closes #1115
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
<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>
|
||||
<td class="text-center"><b>Country</b></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -20,6 +21,17 @@
|
||||
<td class="text-center solve-time">
|
||||
<span data-time="{{ addr.date | isoformat }}"></span>
|
||||
</td>
|
||||
{% set country = lookup_ip_address(addr.ip) %}
|
||||
{% if country %}
|
||||
<td class="text-center">
|
||||
<i class="flag-{{ country.lower() }}"></i>
|
||||
|
||||
{{ lookup_country_code(country) }}
|
||||
</td>
|
||||
{% else %}
|
||||
<td class="text-center">
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
<tr>
|
||||
<td class="text-center"><b>IP Address</b></td>
|
||||
<td class="text-center"><b>Last Seen</b></td>
|
||||
<td class="text-center"><b>Country</b></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -14,6 +15,17 @@
|
||||
<td class="text-center solve-time">
|
||||
<span data-time="{{ addr.date | isoformat }}"></span>
|
||||
</td>
|
||||
{% set country = lookup_ip_address(addr.ip) %}
|
||||
{% if country %}
|
||||
<td class="text-center">
|
||||
<i class="flag-{{ country.lower() }}"></i>
|
||||
|
||||
{{ lookup_country_code(country) }}
|
||||
</td>
|
||||
{% else %}
|
||||
<td class="text-center">
|
||||
</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
</template>
|
||||
|
||||
<div id="team-addresses-modal" class="modal fade">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-action text-center w-100">IP Addresses</h2>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
</div>
|
||||
|
||||
<div id="user-addresses-modal" class="modal fade">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-dialog modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h2 class="modal-action text-center w-100">IP Addresses</h2>
|
||||
|
||||
15
CTFd/utils/countries/geoip.py
Normal file
15
CTFd/utils/countries/geoip.py
Normal file
@@ -0,0 +1,15 @@
|
||||
import geoacumen
|
||||
import maxminddb
|
||||
from flask import current_app
|
||||
|
||||
IP_ADDR_LOOKUP = maxminddb.open_database(
|
||||
current_app.config.get("GEOIP_DATABASE_PATH", geoacumen.db_path)
|
||||
)
|
||||
|
||||
|
||||
def lookup_ip_address(addr):
|
||||
response = IP_ADDR_LOOKUP.get(addr)
|
||||
try:
|
||||
return response["country"]["iso_code"]
|
||||
except KeyError:
|
||||
return None
|
||||
@@ -20,7 +20,6 @@ from CTFd.utils.config import (
|
||||
is_setup,
|
||||
)
|
||||
from CTFd.utils.config.pages import get_pages
|
||||
from CTFd.utils.countries import get_countries, lookup_country_code
|
||||
from CTFd.utils.dates import isoformat, unix_time, unix_time_millis
|
||||
from CTFd.utils.events import EventManager, RedisEventManager
|
||||
from CTFd.utils.humanize.words import pluralize
|
||||
@@ -65,6 +64,8 @@ def init_template_globals(app):
|
||||
registration_visible,
|
||||
scores_visible,
|
||||
)
|
||||
from CTFd.utils.countries import get_countries, lookup_country_code
|
||||
from CTFd.utils.countries.geoip import lookup_ip_address
|
||||
|
||||
app.jinja_env.globals.update(config=config)
|
||||
app.jinja_env.globals.update(get_pages=get_pages)
|
||||
@@ -85,6 +86,7 @@ def init_template_globals(app):
|
||||
app.jinja_env.globals.update(generate_account_url=generate_account_url)
|
||||
app.jinja_env.globals.update(get_countries=get_countries)
|
||||
app.jinja_env.globals.update(lookup_country_code=lookup_country_code)
|
||||
app.jinja_env.globals.update(lookup_ip_address=lookup_ip_address)
|
||||
app.jinja_env.globals.update(accounts_visible=accounts_visible)
|
||||
app.jinja_env.globals.update(challenges_visible=challenges_visible)
|
||||
app.jinja_env.globals.update(registration_visible=registration_visible)
|
||||
|
||||
10
populate.py
10
populate.py
@@ -17,6 +17,7 @@ from CTFd.models import (
|
||||
ChallengeFiles,
|
||||
Fails,
|
||||
Solves,
|
||||
Tracking,
|
||||
)
|
||||
from faker import Faker
|
||||
|
||||
@@ -108,6 +109,10 @@ def gen_file():
|
||||
return fake.file_name()
|
||||
|
||||
|
||||
def gen_ip():
|
||||
return fake.ipv4()
|
||||
|
||||
|
||||
def random_date(start, end):
|
||||
return start + datetime.timedelta(
|
||||
seconds=random.randint(0, int((end - start).total_seconds()))
|
||||
@@ -198,6 +203,11 @@ if __name__ == "__main__":
|
||||
if mode == "teams":
|
||||
user.team_id = random.randint(1, TEAM_AMOUNT)
|
||||
db.session.add(user)
|
||||
db.session.flush()
|
||||
|
||||
track = Tracking(ip=gen_ip(), user_id=user.id)
|
||||
db.session.add(track)
|
||||
db.session.flush()
|
||||
count += 1
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -26,3 +26,5 @@ pydantic==1.5.1
|
||||
lxml==4.5.1
|
||||
html5lib==1.0.1
|
||||
WTForms==2.3.1
|
||||
python-geoacumen==0.0.1
|
||||
maxminddb==1.5.4
|
||||
|
||||
Reference in New Issue
Block a user