Fix rate limit, add favicon
This commit is contained in:
parent
41de5fbf43
commit
e2dbae13ee
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
__pycache__
|
__pycache__
|
||||||
clubhaus/static/**/*
|
clubhaus/static/**/*
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
django.log
|
||||||
|
|
||||||
# Created by https://www.toptal.com/developers/gitignore/api/jetbrains
|
# Created by https://www.toptal.com/developers/gitignore/api/jetbrains
|
||||||
# Edit at https://www.toptal.com/developers/gitignore?templates=jetbrains
|
# Edit at https://www.toptal.com/developers/gitignore?templates=jetbrains
|
||||||
|
@ -139,4 +139,39 @@ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
|
|||||||
IP_RATE_LIMIT_TIME = int(os.getenv("IP_RATE_LIMIT_TIME", "3600"))
|
IP_RATE_LIMIT_TIME = int(os.getenv("IP_RATE_LIMIT_TIME", "3600"))
|
||||||
IP_RATE_LIMIT_COUNT = int(os.getenv("IP_RATE_LIMIT_COUNT", "2"))
|
IP_RATE_LIMIT_COUNT = int(os.getenv("IP_RATE_LIMIT_COUNT", "2"))
|
||||||
|
|
||||||
|
# LOGGING
|
||||||
|
LOGGING = {
|
||||||
|
"version": 1,
|
||||||
|
# The version number of our log
|
||||||
|
"disable_existing_loggers": False,
|
||||||
|
"formatters": {
|
||||||
|
"simple": {
|
||||||
|
"format": "[{levelname}][{asctime}][{funcName}]: {message}",
|
||||||
|
"style": "{",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
# django uses some of its own loggers for internal operations.
|
||||||
|
# In case you want to disable them just replace the False above with true.
|
||||||
|
# A handler for WARNING. It is basically writing the WARNING messages into a file called WARNING.log
|
||||||
|
"handlers": {
|
||||||
|
"file": {
|
||||||
|
"level": "WARNING",
|
||||||
|
"class": "logging.handlers.RotatingFileHandler",
|
||||||
|
"maxBytes": 1024 * 1024 * 5, # 5 MB
|
||||||
|
"backupCount": 5,
|
||||||
|
"filename": BASE_DIR / "django.log",
|
||||||
|
"formatter": "simple",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
# A logger for WARNING which has a handler called 'file'. A logger can have multiple handler
|
||||||
|
"loggers": {
|
||||||
|
# notice the blank '', Usually you would put built in loggers like django or root here based on your needs
|
||||||
|
"": {
|
||||||
|
"handlers": ["file"], # notice how file variable is called in handler which has been defined above
|
||||||
|
"level": "WARNING",
|
||||||
|
"propagate": True,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
# TODO: delete devserver port forward in windows firewall in hammerhead
|
# TODO: delete devserver port forward in windows firewall in hammerhead
|
||||||
|
@ -16,11 +16,15 @@ Including another URLconf
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.conf.urls.static import static
|
from django.conf.urls.static import static
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import path, include
|
from django.urls import path, include, re_path
|
||||||
|
from django.views.generic import RedirectView
|
||||||
|
|
||||||
|
favicon_view = RedirectView.as_view(url='/static/favicon.ico', permanent=True)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', include('homepage.urls')),
|
path('', include('homepage.urls')),
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
|
re_path(r'^favicon\.ico$', favicon_view),
|
||||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
handler400 = "homepage.views.bad_request"
|
handler400 = "homepage.views.bad_request"
|
||||||
|
@ -2,16 +2,16 @@ from django.core import exceptions
|
|||||||
|
|
||||||
|
|
||||||
class RateLimitHit(exceptions.SuspiciousOperation):
|
class RateLimitHit(exceptions.SuspiciousOperation):
|
||||||
def __init__(self):
|
def __init__(self, ip: str):
|
||||||
self.text = "You made to many request in a short period of time! Please try again later"
|
self.text = f"You made to many request in a short period of time! Please try again later. Your IP: {ip}"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.__class__.__name__}: {self.text}"
|
return f"{self.__class__.__name__}: {self.text}"
|
||||||
|
|
||||||
|
|
||||||
class ProxyUsageDetected(exceptions.SuspiciousOperation):
|
class ProxyUsageDetected(exceptions.SuspiciousOperation):
|
||||||
def __init__(self):
|
def __init__(self, proxy: str):
|
||||||
self.text = "It appears you are using a proxy! We don't want you to do that!"
|
self.text = f"It appears you are using a proxy! We don't want you to do that! Your Proxy IP: {proxy}"
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f"{self.__class__.__name__}: {self.text}"
|
return f"{self.__class__.__name__}: {self.text}"
|
||||||
|
BIN
clubhaus/homepage/static/favicon.ico
Normal file
BIN
clubhaus/homepage/static/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 262 KiB |
Binary file not shown.
Before Width: | Height: | Size: 158 KiB |
@ -11,12 +11,12 @@
|
|||||||
<meta property="og:title" content="{% block title %}Clubhaus Schornbach{% endblock %}">
|
<meta property="og:title" content="{% block title %}Clubhaus Schornbach{% endblock %}">
|
||||||
<meta property="og:description" content="Clubhaus Schornbach - est. 2007">
|
<meta property="og:description" content="Clubhaus Schornbach - est. 2007">
|
||||||
<meta property="og:image"
|
<meta property="og:image"
|
||||||
content="{{ request.scheme }}://{{ request.get_host }}{% static 'homepage/logo-with-text.svg' %}">
|
content="https://{{ request.get_host }}{% static 'homepage/logo-with-text.svg' %}">
|
||||||
<meta property="og:type" content="website"/>
|
<meta property="og:type" content="website"/>
|
||||||
<meta property="og:image:type" content="image/svg+xml">
|
<meta property="og:image:type" content="image/svg+xml">
|
||||||
<meta property="og:image:width" content="300">
|
<meta property="og:image:width" content="300">
|
||||||
<meta property="og:image:height" content="300">
|
<meta property="og:image:height" content="300">
|
||||||
<meta property="og:url" content="{{ request.scheme }}://{{ request.get_host }}">
|
<meta property="og:url" content="https://{{ request.get_host }}">
|
||||||
|
|
||||||
<title>Clubhaus Schornbach</title>
|
<title>Clubhaus Schornbach</title>
|
||||||
<link rel="icon" href="{% static 'homepage/logo.svg' %}" sizes="any" type="image/svg+xml">
|
<link rel="icon" href="{% static 'homepage/logo.svg' %}" sizes="any" type="image/svg+xml">
|
||||||
|
@ -142,11 +142,19 @@
|
|||||||
<div class="col-lg-3 col-md-6 mb-lg-0 mb-md-4 mb-3">
|
<div class="col-lg-3 col-md-6 mb-lg-0 mb-md-4 mb-3">
|
||||||
<div class="h-100 p-3 text-white bg-dark rounded-3">
|
<div class="h-100 p-3 text-white bg-dark rounded-3">
|
||||||
<h2><i class="bi-clock display-2"></i></h2>
|
<h2><i class="bi-clock display-2"></i></h2>
|
||||||
|
{% if next_event.date %}
|
||||||
<p class="fs-2 fw-bold">
|
<p class="fs-2 fw-bold">
|
||||||
{{ next_event.date|date:"d.m.Y" }}
|
{{ next_event.date|date:"d.m.Y" }}
|
||||||
<br>
|
<br>
|
||||||
ab {{ next_event.date|date:"H:i" }} Uhr
|
ab {{ next_event.date|date:"H:i" }} Uhr
|
||||||
</p>
|
</p>
|
||||||
|
{% else %}
|
||||||
|
<p class="fs-2 fw-bold">
|
||||||
|
coming
|
||||||
|
<br>
|
||||||
|
soon
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -57,14 +57,14 @@ def voting(request: HttpRequest) -> django.http.HttpResponse:
|
|||||||
request.session.clear_expired()
|
request.session.clear_expired()
|
||||||
|
|
||||||
# Proxy use is forbidden
|
# Proxy use is forbidden
|
||||||
if request.META.get("X-Forwarded-For"):
|
if proxy := request.META.get("HTTP_X_FORWARDED_FOR"):
|
||||||
raise ProxyUsageDetected()
|
raise ProxyUsageDetected(proxy)
|
||||||
|
|
||||||
if request.method != "POST":
|
if request.method != "POST":
|
||||||
return HttpResponseRedirect(reverse("events"))
|
return HttpResponseRedirect(reverse("events"))
|
||||||
|
|
||||||
# Check rate limit
|
# Check rate limit
|
||||||
ip = request.META.get("REMOTE_ADDR")
|
ip = request.META["HTTP_X_REAL_IP"]
|
||||||
cache_key = f"voting_block_{ip}"
|
cache_key = f"voting_block_{ip}"
|
||||||
rate_cache: django.core.cache.BaseCache = cache
|
rate_cache: django.core.cache.BaseCache = cache
|
||||||
if ip not in rate_cache:
|
if ip not in rate_cache:
|
||||||
@ -72,7 +72,7 @@ def voting(request: HttpRequest) -> django.http.HttpResponse:
|
|||||||
rate_cache.incr(cache_key)
|
rate_cache.incr(cache_key)
|
||||||
|
|
||||||
if rate_cache.get(cache_key) > django_settings.IP_RATE_LIMIT_COUNT:
|
if rate_cache.get(cache_key) > django_settings.IP_RATE_LIMIT_COUNT:
|
||||||
raise RateLimitHit()
|
raise RateLimitHit(ip)
|
||||||
|
|
||||||
# check params
|
# check params
|
||||||
if not request.POST["name"]:
|
if not request.POST["name"]:
|
||||||
|
Loading…
Reference in New Issue
Block a user