Compare commits

..

1 Commits

Author SHA1 Message Date
1725ecd4c7 WIP Limit one chat every 30 seconds per IP 2017-12-03 15:54:30 -05:00
15 changed files with 24 additions and 403 deletions

2
.gitignore vendored
View File

@ -1,4 +1,2 @@
server.log
map
map-old
secrets.py

View File

@ -1,10 +1,12 @@
import calendar
import logging
import shlex
import subprocess
import unicodedata
from datetime import datetime, timedelta
import redis
from flask import Flask, request
conn = redis.Redis('localhost')
app = Flask(__name__)
@ -14,31 +16,27 @@ def setup_logging():
app.logger.setLevel(logging.INFO)
def sanitize_input(input):
input = "".join(ch for ch in input if unicodedata.category(ch)[0] != "C")
return shlex.quote(input.replace('^', ''))
@app.route('/chat/', methods=['POST'])
def send_chat():
if request.method == 'POST':
ip = request.headers.get('X-Forwarded-For', request.remote_addr)
recent_ips = conn.hgetall("minecraft_chat_recent_ips")
now = datetime.utcnow()
if ip in recent_ips:
if (now - datetime.fromutctimestamp(recent_ips[ip])) > timedelta.seconds(30):
recent_ips[ip] = calendar.timegm(now.utctimetuple())
if request.form.get('email', None):
return 'Text was entered into honeypot!', 200
if not request.form.get('say-text', None):
return 'No message to send!', 422
if request.form.get('say-username', None):
subprocess.call([
'/usr/bin/screen', '-S', 'mc-panic-shack', '-p', '0', '-X', 'stuff',
'/say [{}]: {}\015'.format(
sanitize_input(request.form['say-username']),
sanitize_input(request.form['say-text']))
])
subprocess.call(['/usr/bin/screen', '-S', 'mc-panic-shack', '-p', '0', '-X', 'stuff',
'/say [{}]: {}\015'.format(request.form['say-username'], request.form['say-text'])])
else:
subprocess.call([
'/usr/bin/screen', '-S', 'mc-panic-shack', '-p', '0', '-X', 'stuff',
'/say {}\015'.format(sanitize_input(request.form['say-text']))
])
subprocess.call(['/usr/bin/screen', '-S', 'mc-panic-shack', '-p', '0', '-X', 'stuff',
'/say {}\015'.format(request.form['say-text'])])
return 'Sending chat: ' + request.form.get('say-username', '') + ': ' + request.form['say-text']
if __name__ == "__main__":
app.run(host='0.0.0.0', port="8888")

View File

@ -1,13 +0,0 @@
[Unit]
Description=Gunicorn instance to serve minecraft-chat wsgi service
After=network.target
[Service]
User=thallada
Group=www-data
WorkingDirectory=/var/www/panic-shack/chat
Environment="PATH=/home/thallada/.virtualenvs/minecraft-chat/bin"
ExecStart=/home/thallada/.virtualenvs/minecraft-chat/bin/gunicorn --workers 1 --bind unix:minecraft-chat.sock -m 007 server:app --log-file /srv/minecraft-panic-shack/gunicorn.log
[Install]
WantedBy=multi-user.target

View File

@ -1,50 +0,0 @@
[Unit]
Description=Minecraft Server %i
After=network.target
[Service]
WorkingDirectory=/srv/minecraft-%i
User=thallada
Group=thallada
ProtectSystem=full
ProtectHome=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
ExecStart=/bin/sh -c '/usr/bin/screen -DmLS mc-%i /usr/bin/java -server -Xms1G -Xmx2G -XX:+UseG1GC -XX:+CMSIncrementalPacing -XX:+CMSClassUnloadingEnabled -XX:ParallelGCThreads=2 -XX:MinHeapFreeRatio=5 -XX:MaxHeapFreeRatio=10 -jar $(ls -v | grep -i "FTBServer.*jar\|minecraft_server.*jar" | head -n 1) nogui'
ExecReload=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "reload"\\015'
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 15 SECONDS..."\015'
ExecStop=/bin/sleep 5
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 10 SECONDS..."\015'
ExecStop=/bin/sleep 5
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN IN 5 SECONDS..."\015'
ExecStop=/bin/sleep 5
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "say SERVER SHUTTING DOWN. Saving map..."\\015'
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "save-all"\\015'
ExecStop=/usr/bin/screen -p 0 -S mc-%i -X eval 'stuff "stop"\\015'
ExecStop=/bin/sleep 2
Restart=on-failure
RestartSec=60s
[Install]
WantedBy=multi-user.target
#########
# HowTo
#########
#
# Create directory in /opt/minecraft-XX where XX is a name like 'survival'
# Add minecraft_server.jar into dir with other conf files for minecraft server
#
# Enable/Start systemd service
# systemctl enable minecraft@survival
# systemctl start minecraft@survival
#
# To run multiple servers simply create a new dir structure and enable/start it
# systemctl enable minecraft@creative
# systemctl start minecraft@creative

View File

@ -1,12 +0,0 @@
server {
listen 80;
listen [::]:80;
root /var/www/panic-shack;
server_name panic-shack.hallada.net;
location / {
return 301 https://panic-shack.hallada.net$request_uri;
}
}

View File

@ -1,36 +0,0 @@
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name panic-shack.hallada.net;
root /var/www/panic-shack;
ssl_certificate /etc/letsencrypt/live/panic-shack.hallada.net/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/panic-shack.hallada.net/privkey.pem;
ssl_trusted_certificate /etc/letsencrypt/live/panic-shack.hallada.net/fullchain.pem;
location /notify {
deny all;
return 404;
}
location /config {
deny all;
return 404;
}
location / {
try_files $uri $uri/ $uri.php?$args =404;
}
location /old-worlds {
autoindex on;
try_files $uri $uri/ $uri.php?$args =404;
}
location /chat {
include uwsgi_params;
proxy_set_header X-Forwarded-Host $host:$server_port; proxy_set_header X-Forwarded-Server $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_pass http://unix:/var/www/panic-shack/chat/minecraft-chat.sock;
}
}

View File

@ -1,130 +0,0 @@
worlds["Death Pit"] = "/srv/minecraft-panic-shack/world"
renders["normalrender"] = {
"world": "Death Pit",
"title": "North",
"rendermode": smooth_lighting,
"dimension": "overworld",
"northdirection": "upper-left",
}
renders["normalrendersouth"] = {
"world": "Death Pit",
"title": "South",
"rendermode": smooth_lighting,
"dimension": "overworld",
"northdirection": "lower-right",
}
renders["normalrenderwest"] = {
"world": "Death Pit",
"title": "West",
"rendermode": smooth_lighting,
"dimension": "overworld",
"northdirection": "upper-right",
}
renders["normalrendereast"] = {
"world": "Death Pit",
"title": "East",
"rendermode": smooth_lighting,
"dimension": "overworld",
"northdirection": "lower-left",
}
renders["nightrender"] = {
"world": "Death Pit",
"title": "Night North",
"rendermode": smooth_night,
"dimension": "overworld",
"northdirection": "upper-left",
}
renders["nightrendersouth"] = {
"world": "Death Pit",
"title": "Night South",
"rendermode": smooth_night,
"dimension": "overworld",
"northdirection": "lower-right",
}
renders["nightrenderwest"] = {
"world": "Death Pit",
"title": "Night West",
"rendermode": smooth_night,
"dimension": "overworld",
"northdirection": "upper-right",
}
renders["nightrendereast"] = {
"world": "Death Pit",
"title": "Night East",
"rendermode": smooth_night,
"dimension": "overworld",
"northdirection": "lower-left",
}
renders["caverender"] = {
"world": "Death Pit",
"title": "Cave North",
"rendermode": cave,
"dimension": "overworld",
"northdirection": "upper-left",
}
renders["caverendersouth"] = {
"world": "Death Pit",
"title": "Cave South",
"rendermode": cave,
"dimension": "overworld",
"northdirection": "lower-right",
}
renders["caverenderwest"] = {
"world": "Death Pit",
"title": "Cave West",
"rendermode": cave,
"dimension": "overworld",
"northdirection": "upper-right",
}
renders["caverendereast"] = {
"world": "Death Pit",
"title": "Cave East",
"rendermode": cave,
"dimension": "overworld",
"northdirection": "lower-left",
}
renders["netherrender"] = {
"world": "Death Pit",
"title": "Nether North",
"rendermode": nether,
"dimension": "nether",
"northdirection": "upper-left",
}
renders["netherrendersouth"] = {
"world": "Death Pit",
"title": "Nether South",
"rendermode": nether,
"dimension": "nether",
"northdirection": "lower-right",
}
renders["netherrenderwest"] = {
"world": "Death Pit",
"title": "Nether West",
"rendermode": nether,
"dimension": "nether",
"northdirection": "upper-right",
}
renders["netherrendereast"] = {
"world": "Death Pit",
"title": "Nether East",
"rendermode": nether,
"dimension": "nether",
"northdirection": "lower-left",
}
outputdir = "/var/www/panic-shack/map/"

View File

@ -68,7 +68,7 @@ ol li code {
margin-bottom: 2px;
}
.map-link {
#map-link {
display: block;
text-align: center;
}
@ -130,18 +130,3 @@ ol li code {
margin-top: 5px;
margin-bottom: 0;
}
.maintenance-notice {
padding: 20px;
background: darkred;
color: white;
}
.maintenance-notice h3 {
margin: 0;
margin-right: 20px;
}
.maintenance-notice h3,span {
display: inline-block;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 496 KiB

View File

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

@ -7,13 +7,9 @@
<meta charset="UTF-8">
</head>
<body>
<!-- <div class="maintenance-notice"> -->
<!-- <h3>Server is down</h3> -->
<!-- <span>ETA: 15 hours for generating a new Minecraft 1.13 map.</span> -->
<!-- </div> -->
<div class="width-limit">
<h1>Panic Shack - Minecraft Server</h1>
<img src="img/deathpit_shader_sm.png" alt="Screenshot from the Minecraft server of the swamp and the large house in the distance">
<img src="img/bridge.jpg" alt="Screenshot from the Minecraft server of a bridge over a lake in a jungle biome">
<h2>Server Status</h2>
<div id="server-status-error">
@ -64,7 +60,6 @@
<h2>How to Connect</h2>
<ol>
<li>Email me at tyler@hallada.net with your Minecraft username to request to join the server</li>
<li>Launch Minecraft (version <span id="info-server-name">1.12.2</span>)</li>
<li>Go to "Multiplayer"</li>
<li>Click "Add Server"</li>
@ -74,22 +69,16 @@
<li>You should now see the server in the list and be able to join it!</li>
</ol>
<h2>Server Maps</h2>
<a href="map/" class="map-link">
<img src="img/deathpit.png" alt="Screenshot from the in-browser map of the death pit server">
View Death Pit map
<h2>Server Map</h2>
<a href="map/" id="map-link">
<img src="img/map.jpg" alt="Screenshot from the in-browser map of the server centered on the lake and bridge">
View the server map
</a>
<p class="small-text">
This map is updated every day around 3 am EST. Last updated:&nbsp;
<span id="map-last-updated" class="small-text"></span><br>
</p>
<a href="map-old/" class="map-link">
<img src="img/map-old.jpg" alt="Screenshot from the in-browser map of the panic-shack server centered on the lake and bridge">
View Panic Shack map
</a>
<p class="small-text">
This map was last updated: 04/04/2019.
Map is updated every day around 3 am EST. Last updated:&nbsp;
<span id="map-last-updated" class="small-text"></span>
</p>
<h2>Server Log</h2>
</div>
<pre id="server-log"></pre>
@ -120,59 +109,6 @@
<span id="say-error" class="inline"></span>
<p id="say-notice" class="small-text">It may take a minute or two before the message appears in the above server log.</p>
</form>
<hr>
<h2>Download Old Worlds</h2>
<p>
<a href="/old-worlds">Visit here to download all of the previous worlds on this server.</a> You can load
them in Minecraft and play them in single player by following
<a href="https://minecraft.gamepedia.com/Tutorials/Map_downloads">these instructions</a>.
</p>
<h2>Notices</h2>
<p>
<ul>
<li>
<strong>September 5, 2020</strong>
Server is back up and running on Minecraft 1.16.2 with a new map.
</li>
<li>
<strong>May 18, 2020</strong>
Hibernating this server for a while to save resources for a 7DaysToDie server instead.
</li>
<li>
<strong>April 19, 2020</strong>
I switched the server over to a Spigot 1.15.2 server with the Vivecraft extension installed.
</li>
<li>
<strong>July 14, 2019:</strong>
Upgraded the server to 1.14.3 and regenerated the map. It's now using the seed "hardlead".
</li>
<li>
<strong>August 22, 2018:</strong>
Upgraded the server yet again to 1.13.1.
</li>
<li>
<strong>August 22, 2018:</strong>
The map should now be updating again nightly at 3 am EST.
</li>
<li>
<strong>August 16, 2018:</strong>
I upgraded the server to Minecraft version 1.13. The map is no longer working on this version and
won't update. I'll upgrade the map once it supports 1.13.
</li>
<li>
<strong>April 15, 2018:</strong>
The server has a user white-list. If you are not added to it then you cannot join the server.
Email me at tyler@hallada.net to request to join the server.
</li>
<li>
<strong>April 13, 2018:</strong>
I doubled the memory on the server so the server shouldn't keep running out of memory and crashing.
</li>
</ul>
</p>
</div>
<script src="https://mcapi.us/scripts/minecraft.js"></script>

View File

@ -1,52 +0,0 @@
#!/usr/bin/env python
# Read the Minecraft server log and diff it against the server log it saw last. If there any new joins in the diff, send
# a notification.
import codecs
import os
import re
from datetime import datetime
import requests
from secrets import IFTTT_WEBHOOK_KEY_TYLER, IFTTT_WEBHOOK_KEY_KAELAN
LOG_FILENAME = '/srv/minecraft-panic-shack/logs/latest.log'
OLD_LOG_FILENAME = '/srv/minecraft-panic-shack/logs/last-read.log'
USERNAME_BLACKLIST = ['anarchyeight', 'kinedactyl']
IFTTT_EVENT_NAME = 'user_joined_panic_shack'
def read_log(filename):
with codecs.open(filename, encoding='utf-8') as log:
return log.readlines()
def save_log(filename, lines):
with codecs.open(filename, 'w', encoding='utf-8') as log:
log.writelines(lines)
if __name__ == '__main__':
if (datetime.fromtimestamp(os.path.getmtime(LOG_FILENAME)) >
datetime.fromtimestamp(os.path.getmtime(OLD_LOG_FILENAME))):
new_log = read_log(LOG_FILENAME)
old_log = read_log(OLD_LOG_FILENAME)
if new_log[0] != old_log[0]:
# A log rotate occured
old_log = []
if len(new_log) > len(old_log):
for new_line in new_log[len(old_log):]:
match = re.match('[\[][0-9:]+[\]]\s[\[]Server thread/INFO]: (\S+) joined the game', new_line)
if match:
username = match.group(1)
if username not in USERNAME_BLACKLIST:
# IFTTT does not support sharing Applets anymore :(
r = requests.post(
'https://maker.ifttt.com/trigger/{}/with/key/{}'.format(IFTTT_EVENT_NAME,
IFTTT_WEBHOOK_KEY_TYLER),
data={'value1': username})
r = requests.post(
'https://maker.ifttt.com/trigger/{}/with/key/{}'.format(IFTTT_EVENT_NAME,
IFTTT_WEBHOOK_KEY_KAELAN),
data={'value1': username})
save_log(OLD_LOG_FILENAME, new_log)

View File

@ -1 +0,0 @@
/srv/minecraft-panic-shack/old-worlds

View File

@ -1,2 +0,0 @@
[flake8]
max_line_length = 120