mirror of https://github.com/cocosolos/ixion.git
Add geolocation and variable pruning
This commit is contained in:
parent
34b498cbfc
commit
b1387b79e2
|
|
@ -8,13 +8,11 @@
|
|||
#
|
||||
# Note that binary is a macro for -text -diff.
|
||||
######################################################################
|
||||
|
||||
# Auto detect
|
||||
## Handle line endings automatically for files detected as
|
||||
## text and leave all files detected as binary untouched.
|
||||
## This will handle all files NOT defined below.
|
||||
* text=auto
|
||||
|
||||
# Source code
|
||||
*.bash text eol=lf
|
||||
*.bat text eol=crlf
|
||||
|
|
@ -52,10 +50,8 @@
|
|||
*.tsx text
|
||||
*.xml text
|
||||
*.xhtml text diff=html
|
||||
|
||||
# Docker
|
||||
Dockerfile text
|
||||
|
||||
# Documentation
|
||||
*.ipynb text eol=lf
|
||||
*.markdown text diff=markdown
|
||||
|
|
@ -81,7 +77,6 @@ NEWS text
|
|||
readme text
|
||||
*README* text
|
||||
TODO text
|
||||
|
||||
# Templates
|
||||
*.dot text
|
||||
*.ejs text
|
||||
|
|
@ -100,7 +95,6 @@ TODO text
|
|||
*.tpl text
|
||||
*.twig text
|
||||
*.vue text
|
||||
|
||||
# Configs
|
||||
*.cnf text
|
||||
*.conf text
|
||||
|
|
@ -124,10 +118,8 @@ Makefile text
|
|||
makefile text
|
||||
# Fixes syntax highlighting on GitHub to allow comments
|
||||
tsconfig.json linguist-language=JSON-with-Comments
|
||||
|
||||
# Heroku
|
||||
Procfile text
|
||||
|
||||
# Graphics
|
||||
*.ai binary
|
||||
*.bmp binary
|
||||
|
|
@ -155,7 +147,6 @@ Procfile text
|
|||
*.tiff binary
|
||||
*.wbmp binary
|
||||
*.webp binary
|
||||
|
||||
# Audio
|
||||
*.kar binary
|
||||
*.m4a binary
|
||||
|
|
@ -164,7 +155,6 @@ Procfile text
|
|||
*.mp3 binary
|
||||
*.ogg binary
|
||||
*.ra binary
|
||||
|
||||
# Video
|
||||
*.3gpp binary
|
||||
*.3gp binary
|
||||
|
|
@ -184,7 +174,6 @@ Procfile text
|
|||
*.swc binary
|
||||
*.swf binary
|
||||
*.webm binary
|
||||
|
||||
# Archives
|
||||
*.7z binary
|
||||
*.gz binary
|
||||
|
|
@ -192,26 +181,22 @@ Procfile text
|
|||
*.rar binary
|
||||
*.tar binary
|
||||
*.zip binary
|
||||
|
||||
# Fonts
|
||||
*.ttf binary
|
||||
*.eot binary
|
||||
*.otf binary
|
||||
*.woff binary
|
||||
*.woff2 binary
|
||||
|
||||
# Executables
|
||||
*.exe binary
|
||||
*.pyc binary
|
||||
# Prevents massive diffs caused by vendored, minified files
|
||||
**/.yarn/releases/** binary
|
||||
**/.yarn/plugins/** binary
|
||||
|
||||
# RC files (like .babelrc or .eslintrc)
|
||||
*.*rc text
|
||||
|
||||
# Ignore files (like .npmignore or .gitignore)
|
||||
*.*ignore text
|
||||
|
||||
# Prevents massive diffs from built files
|
||||
dist/* binary
|
||||
*.mmdb filter=lfs diff=lfs merge=lfs -text
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ Ixion is designed to catalog public [LandSandBoat](https://github.com/LandSandBo
|
|||
|
||||
The React client fetches server data from the API and displays it in a relevant way to users. Filtering is built into the client for now. When the API response fails or is empty, a default LSB demo server is displayed, pulling some info from GitHub.
|
||||
|
||||
[IP Geolocation by DB-IP](https://db-ip.com)
|
||||
|
||||
## Features
|
||||
|
||||
- **Automatic Verification**: Verifies LSB server URL by sending a request to the public API. [Requires the LSB server to enable the HTTP server.](https://github.com/LandSandBoat/server/blob/df311283c4abb779d212e2b8af6734b0d8d11ad7/settings/default/network.lua#L33)
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@ CSRF_TRUSTED_ORIGINS=https://api.ixion.dev
|
|||
CORS_ALLOWED_ORIGINS=https://ixion.dev
|
||||
|
||||
# API configuration
|
||||
SERVER_INACTIVITY_TIMEOUT=24
|
||||
SERVER_UPDATE_INTERVAL=10
|
||||
|
|
|
|||
|
|
@ -26,7 +26,9 @@ app.conf.result_backend = f"redis://redis:6379"
|
|||
app.conf.beat_schedule = {
|
||||
"verify-urls-every-hour": {
|
||||
"task": "api.tasks.verify_urls_task",
|
||||
"schedule": timedelta(hours=1),
|
||||
"schedule": timedelta(
|
||||
minutes=int(os.getenv("SERVER_UPDATE_INTERVAL", default="10"))
|
||||
),
|
||||
# "schedule": timedelta(minutes=1),
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ INSTALLED_APPS = [
|
|||
"django.contrib.staticfiles",
|
||||
"corsheaders",
|
||||
"rest_framework",
|
||||
"geoip2",
|
||||
"v1",
|
||||
]
|
||||
|
||||
|
|
@ -139,3 +140,5 @@ CORS_ALLOWED_ORIGINS = os.getenv(
|
|||
CORS_ALLOW_ALL_ORIGINS = (
|
||||
os.getenv("CORS_ALLOW_ALL_ORIGINS", default="False").lower() == "true"
|
||||
)
|
||||
|
||||
GEOIP_PATH = os.path.join(BASE_DIR, "geoip")
|
||||
|
|
|
|||
|
|
@ -6,3 +6,4 @@ celery
|
|||
redis
|
||||
python-dotenv
|
||||
gunicorn
|
||||
geoip2
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 5.0.4 on 2024-04-22 19:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('v1', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='server',
|
||||
name='location',
|
||||
field=models.CharField(editable=False, max_length=255, null=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# Generated by Django 5.0.4 on 2024-04-22 20:10
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('v1', '0002_server_location'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='server',
|
||||
name='inactivity_counter',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='server',
|
||||
name='up',
|
||||
field=models.BooleanField(editable=False, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='server',
|
||||
name='updated',
|
||||
field=models.DateTimeField(editable=False, null=True),
|
||||
),
|
||||
]
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
import datetime
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
|
|
@ -7,6 +8,7 @@ from django.core.validators import URLValidator
|
|||
from django.core.exceptions import ValidationError
|
||||
from urllib.parse import urlparse
|
||||
from v1.common.logging import logger
|
||||
from django.contrib.gis.geoip2 import GeoIP2
|
||||
|
||||
# Required and recommended settings used to build the initial client server card
|
||||
required_settings = [
|
||||
|
|
@ -41,14 +43,20 @@ class Server(models.Model):
|
|||
null=False,
|
||||
validators=[OptionalSchemeURLValidator()],
|
||||
)
|
||||
location = models.CharField(max_length=255, null=True, editable=False)
|
||||
max_level = models.IntegerField(null=True, editable=False)
|
||||
settings = models.JSONField(null=True, editable=False)
|
||||
customizations = models.JSONField(null=True, editable=False)
|
||||
login_limit = models.IntegerField(null=True, editable=False)
|
||||
active_sessions = models.IntegerField(null=True, editable=False)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
updated = models.DateTimeField(auto_now=True)
|
||||
inactivity_counter = models.IntegerField(null=True, editable=False)
|
||||
updated = models.DateTimeField(null=True, editable=False)
|
||||
up = models.BooleanField(null=True, editable=False)
|
||||
|
||||
@property
|
||||
def expires(self):
|
||||
time_since_creation = self.updated - self.created
|
||||
return self.updated + min(time_since_creation, datetime.timedelta(hours=24))
|
||||
|
||||
def _str_(self):
|
||||
return self.url
|
||||
|
|
@ -69,17 +77,14 @@ class Server(models.Model):
|
|||
|
||||
# Validate the server API
|
||||
if not self.parse_server_api():
|
||||
if (
|
||||
self.inactivity_counter is None
|
||||
or self.inactivity_counter
|
||||
>= int(os.getenv("SERVER_INACTIVITY_TIMEOUT", default="24")) - 1
|
||||
):
|
||||
if self.expires <= datetime.datetime.now(datetime.timezone.utc):
|
||||
return False
|
||||
self.inactivity_counter += 1
|
||||
self.up = False
|
||||
else:
|
||||
if self.settings["API.DO_NOT_TRACK"]:
|
||||
return False
|
||||
self.inactivity_counter = 0
|
||||
self.up = True
|
||||
self.updated = datetime.datetime.now(datetime.timezone.utc)
|
||||
|
||||
# Proceed with saving the object
|
||||
logger.info(f"Saving Server object with URL: {self.url}")
|
||||
|
|
@ -142,6 +147,10 @@ class Server(models.Model):
|
|||
# except socket.error:
|
||||
# return False
|
||||
|
||||
g = GeoIP2()
|
||||
city = g.city(f"{self.url}")
|
||||
self.location = city["continent_code"]
|
||||
|
||||
return True
|
||||
|
||||
except requests.RequestException:
|
||||
|
|
|
|||
|
|
@ -10,12 +10,13 @@ class ServerSerializer(serializers.ModelSerializer):
|
|||
"id",
|
||||
"name",
|
||||
"url",
|
||||
"location",
|
||||
"max_level",
|
||||
"customizations",
|
||||
"login_limit",
|
||||
"active_sessions",
|
||||
"updated",
|
||||
"inactivity_counter",
|
||||
"up",
|
||||
]
|
||||
|
||||
def create(self, validated_data):
|
||||
|
|
|
|||
|
|
@ -142,32 +142,57 @@ export default function ServerCard({ server }: { server: ServerData }) {
|
|||
<Card className="mb-2">
|
||||
<Accordion className="my-0">
|
||||
<AccordionSummary expandIcon={<ExpandMore />}>
|
||||
<Box className="flex items-center justify-center">
|
||||
{server.customizations['LOGIN.MAINT_MODE'] === 1 ? (
|
||||
<Box className="flex flex-col items-center justify-center">
|
||||
<Box className="flex content-center">
|
||||
{server.customizations['LOGIN.MAINT_MODE'] === 1 ? (
|
||||
<Tooltip
|
||||
arrow
|
||||
disableInteractive
|
||||
title="Server is undergoing maintenance."
|
||||
>
|
||||
<Warning color="warning" />
|
||||
</Tooltip>
|
||||
) : (
|
||||
<div>
|
||||
{!server.up ? (
|
||||
<Tooltip
|
||||
arrow
|
||||
disableInteractive
|
||||
title="Server is offline."
|
||||
>
|
||||
<PublicOff color="error" />
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip arrow disableInteractive title="Server is online.">
|
||||
<Public color="success" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Box>
|
||||
<Box className="flex content-center">
|
||||
<Tooltip
|
||||
arrow
|
||||
disableInteractive
|
||||
title="Server is undergoing maintenance."
|
||||
title="Estimated server geolocation provided by DB-IP."
|
||||
>
|
||||
<Warning color="warning" />
|
||||
<Typography
|
||||
variant="caption"
|
||||
component={Link}
|
||||
to="https://db-ip.com"
|
||||
target="_blank"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
sx={{
|
||||
textDecoration: 'none',
|
||||
}}
|
||||
color={(theme) => alpha(theme.palette.text.primary, 0.5)}
|
||||
>
|
||||
{server.location}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<div>
|
||||
{server.inactivity_counter > 0 ? (
|
||||
<Tooltip
|
||||
arrow
|
||||
disableInteractive
|
||||
title={`Offline for ${server.inactivity_counter} hours.`}
|
||||
>
|
||||
<PublicOff color="error" />
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip arrow disableInteractive title="Server is online.">
|
||||
<Public color="success" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<CardContent className="grow py-1">
|
||||
<Box className="flex content-center">
|
||||
|
|
|
|||
|
|
@ -15,19 +15,21 @@ export default interface ServerData {
|
|||
id: number;
|
||||
name: string;
|
||||
url: string;
|
||||
location: string;
|
||||
max_level: number;
|
||||
settings?: ServerSettings;
|
||||
customizations: ServerSettings;
|
||||
login_limit: number;
|
||||
active_sessions: number;
|
||||
updated: string;
|
||||
inactivity_counter: number;
|
||||
up: boolean;
|
||||
}
|
||||
|
||||
export const DemoServerData: ServerData = {
|
||||
id: 0,
|
||||
name: 'LandSandBoat Demo',
|
||||
url: 'github.com/LandSandBoat/server',
|
||||
location: 'NA',
|
||||
max_level: 99,
|
||||
settings: LsbDefaults,
|
||||
customizations: {
|
||||
|
|
@ -43,7 +45,7 @@ export const DemoServerData: ServerData = {
|
|||
login_limit: 0,
|
||||
active_sessions: 0,
|
||||
updated: new Date().toISOString(),
|
||||
inactivity_counter: 0,
|
||||
up: true,
|
||||
};
|
||||
|
||||
export const ServerSettingsInfo: Record<string, ServerSetting> = {
|
||||
|
|
|
|||
|
|
@ -108,32 +108,61 @@ export default function ServerDetails({
|
|||
) : (
|
||||
<Card className="mb-2">
|
||||
<Box className="flex px-4">
|
||||
<Box className="flex items-center justify-center">
|
||||
{server.customizations['LOGIN.MAINT_MODE'] === 1 ? (
|
||||
<Box className="flex flex-col items-center justify-center">
|
||||
<Box className="flex content-center">
|
||||
{server.customizations['LOGIN.MAINT_MODE'] === 1 ? (
|
||||
<Tooltip
|
||||
arrow
|
||||
disableInteractive
|
||||
title="Server is undergoing maintenance."
|
||||
>
|
||||
<Warning color="warning" />
|
||||
</Tooltip>
|
||||
) : (
|
||||
<div>
|
||||
{!server.up ? (
|
||||
<Tooltip
|
||||
arrow
|
||||
disableInteractive
|
||||
title="Server is offline."
|
||||
>
|
||||
<PublicOff color="error" />
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip
|
||||
arrow
|
||||
disableInteractive
|
||||
title="Server is online."
|
||||
>
|
||||
<Public color="success" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Box>
|
||||
<Box className="flex content-center">
|
||||
<Tooltip
|
||||
arrow
|
||||
disableInteractive
|
||||
title="Server is undergoing maintenance."
|
||||
title="Estimated server geolocation provided by DB-IP"
|
||||
>
|
||||
<Warning color="warning" />
|
||||
<Typography
|
||||
variant="caption"
|
||||
component={Link}
|
||||
to="https://db-ip.com"
|
||||
target="_blank"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
sx={{
|
||||
textDecoration: 'none',
|
||||
}}
|
||||
color={(theme) => alpha(theme.palette.text.primary, 0.5)}
|
||||
>
|
||||
{server.location}
|
||||
</Typography>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<div>
|
||||
{server.inactivity_counter > 0 ? (
|
||||
<Tooltip
|
||||
arrow
|
||||
disableInteractive
|
||||
title={`Offline for ${server.inactivity_counter} hours.`}
|
||||
>
|
||||
<PublicOff color="error" />
|
||||
</Tooltip>
|
||||
) : (
|
||||
<Tooltip arrow disableInteractive title="Server is online.">
|
||||
<Public color="success" />
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</Box>
|
||||
</Box>
|
||||
<CardContent className="grow py-1">
|
||||
<Box className="flex content-center">
|
||||
|
|
|
|||
Loading…
Reference in New Issue