Compare commits
7 Commits
cb5666e9b9
...
master
Author | SHA1 | Date | |
---|---|---|---|
![]() |
d71d33cfe0 | ||
![]() |
8d29328103 | ||
![]() |
748b4e47a2 | ||
![]() |
6935cefaf7 | ||
![]() |
1a62bbae2a | ||
![]() |
3d54f95a01 | ||
![]() |
9cc6730291 |
97
app.py
97
app.py
@@ -63,17 +63,23 @@ def load_user(user_id):
|
|||||||
return User.query.get(int(user_id))
|
return User.query.get(int(user_id))
|
||||||
|
|
||||||
def get_real_ip():
|
def get_real_ip():
|
||||||
if "CF-Connecting-IP" in request.headers:
|
headers = request.headers
|
||||||
return request.headers.get("CF-Connecting-IP")
|
cf_ip = headers.get("CF-Connecting-IP")
|
||||||
elif "X-Real-IP" in request.headers:
|
if cf_ip:
|
||||||
return request.headers.get("X-Real-IP")
|
return cf_ip.split(",")[0].strip()
|
||||||
elif "X-Forwarded-For" in request.headers:
|
xff = headers.get("X-Forwarded-For")
|
||||||
forwarded_for = request.headers.get("X-Forwarded-For").split(",")
|
if xff:
|
||||||
return forwarded_for[0].strip()
|
return xff.split(",")[0].strip()
|
||||||
|
x_real_ip = headers.get("X-Real-IP")
|
||||||
|
if x_real_ip:
|
||||||
|
return x_real_ip.strip()
|
||||||
return request.remote_addr
|
return request.remote_addr
|
||||||
|
|
||||||
|
|
||||||
def is_allowed_ip(remote_ip, allowed_hosts_str):
|
def is_allowed_ip(remote_ip, allowed_hosts_str):
|
||||||
|
if remote_ip in ("127.0.0.1", "::1"):
|
||||||
|
return True
|
||||||
|
|
||||||
if os.path.exists("emergency_access.txt"):
|
if os.path.exists("emergency_access.txt"):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@@ -89,7 +95,6 @@ def is_allowed_ip(remote_ip, allowed_hosts_str):
|
|||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Log reverse DNS dla IP odwiedzającego
|
|
||||||
try:
|
try:
|
||||||
hostname = socket.gethostbyaddr(remote_ip)[0]
|
hostname = socket.gethostbyaddr(remote_ip)[0]
|
||||||
app.logger.info(f"Odwiedzający IP: {remote_ip}, host: {hostname}")
|
app.logger.info(f"Odwiedzający IP: {remote_ip}, host: {hostname}")
|
||||||
@@ -98,11 +103,19 @@ def is_allowed_ip(remote_ip, allowed_hosts_str):
|
|||||||
|
|
||||||
return remote_ip in allowed_ips
|
return remote_ip in allowed_ips
|
||||||
|
|
||||||
|
|
||||||
# Dodaj filtr Markdown – pozwala na zagnieżdżanie linków i obrazków w opisie
|
# Dodaj filtr Markdown – pozwala na zagnieżdżanie linków i obrazków w opisie
|
||||||
@app.template_filter('markdown')
|
@app.template_filter('markdown')
|
||||||
def markdown_filter(text):
|
def markdown_filter(text):
|
||||||
return Markup(md.markdown(text))
|
return Markup(md.markdown(text))
|
||||||
|
|
||||||
|
@app.context_processor
|
||||||
|
def inject_ip_allowed():
|
||||||
|
settings = GlobalSettings.query.first()
|
||||||
|
allowed_hosts_str = settings.allowed_login_hosts if settings and settings.allowed_login_hosts else ""
|
||||||
|
client_ip = get_real_ip()
|
||||||
|
return {'is_ip_allowed': is_allowed_ip(client_ip, allowed_hosts_str)}
|
||||||
|
|
||||||
# TRASY PUBLICZNE
|
# TRASY PUBLICZNE
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
@@ -324,20 +337,46 @@ def create_admin_account():
|
|||||||
db.session.add(main_admin)
|
db.session.add(main_admin)
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
|
|
||||||
|
|
||||||
@app.after_request
|
@app.after_request
|
||||||
def add_security_headers(response):
|
def apply_headers(response):
|
||||||
|
# Nagłówki niestandardowe
|
||||||
|
custom_headers = app.config.get("ADD_HEADERS", {})
|
||||||
|
if isinstance(custom_headers, dict):
|
||||||
|
for header, value in custom_headers.items():
|
||||||
|
response.headers[header] = str(value)
|
||||||
|
|
||||||
|
# Wykluczenia
|
||||||
|
if response.status_code in (301, 302, 303, 307, 308):
|
||||||
|
response.headers.pop("Vary", None)
|
||||||
|
return response
|
||||||
|
|
||||||
|
if 400 <= response.status_code < 500:
|
||||||
|
response.headers["Cache-Control"] = "no-store"
|
||||||
|
response.headers["Content-Type"] = "text/html; charset=utf-8"
|
||||||
|
response.headers.pop("Vary", None)
|
||||||
|
elif 500 <= response.status_code < 600:
|
||||||
|
response.headers["Cache-Control"] = "no-store"
|
||||||
|
response.headers["Content-Type"] = "text/html; charset=utf-8"
|
||||||
|
response.headers["Retry-After"] = "120"
|
||||||
|
response.headers.pop("Vary", None)
|
||||||
|
elif request.path.startswith("/admin"):
|
||||||
|
response.headers.pop("Vary", None)
|
||||||
|
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
|
||||||
|
else:
|
||||||
|
response.headers["Vary"] = "Cookie, Accept-Encoding"
|
||||||
|
default_cache = app.config.get("CACHE_CONTROL_HEADER") or "private, max-age=0"
|
||||||
|
response.headers["Cache-Control"] = default_cache
|
||||||
|
|
||||||
|
# Blokowanie botów
|
||||||
if app.config.get("BLOCK_BOTS", False):
|
if app.config.get("BLOCK_BOTS", False):
|
||||||
cache_control = app.config.get("CACHE_CONTROL_HEADER")
|
cc = app.config.get("CACHE_CONTROL_HEADER") or "no-store, no-cache, must-revalidate, max-age=0"
|
||||||
if cache_control:
|
response.headers["Cache-Control"] = cc
|
||||||
response.headers["Cache-Control"] = cache_control
|
response.headers["X-Robots-Tag"] = app.config.get("ROBOTS_TAG") or "noindex, nofollow, nosnippet, noarchive"
|
||||||
# Jeśli Cache-Control jest ustawiony, usuwamy Pragma
|
|
||||||
response.headers.pop("Pragma", None)
|
|
||||||
else:
|
|
||||||
response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, max-age=0"
|
|
||||||
response.headers["Pragma"] = app.config.get("PRAGMA_HEADER", "no-cache")
|
|
||||||
response.headers["X-Robots-Tag"] = app.config.get("ROBOTS_TAG", "noindex, nofollow, nosnippet, noarchive")
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
@app.route('/admin/settings', methods=['GET', 'POST'])
|
@app.route('/admin/settings', methods=['GET', 'POST'])
|
||||||
@login_required
|
@login_required
|
||||||
def admin_settings():
|
def admin_settings():
|
||||||
@@ -392,28 +431,6 @@ def robots():
|
|||||||
robots_txt = "User-agent: *\nAllow: /"
|
robots_txt = "User-agent: *\nAllow: /"
|
||||||
return robots_txt, 200, {'Content-Type': 'text/plain'}
|
return robots_txt, 200, {'Content-Type': 'text/plain'}
|
||||||
|
|
||||||
@app.route('/debug/headers')
|
|
||||||
def debug_headers():
|
|
||||||
ip_sources = {
|
|
||||||
"CF-Connecting-IP": request.headers.get("CF-Connecting-IP"),
|
|
||||||
"X-Real-IP": request.headers.get("X-Real-IP"),
|
|
||||||
"X-Forwarded-For": request.headers.get("X-Forwarded-For"),
|
|
||||||
"remote_addr": request.remote_addr,
|
|
||||||
}
|
|
||||||
|
|
||||||
all_headers = dict(request.headers)
|
|
||||||
|
|
||||||
response_html = "<h2>Nagłówki IP</h2><ul>"
|
|
||||||
for key, val in ip_sources.items():
|
|
||||||
response_html += f"<li><strong>{key}:</strong> {val}</li>"
|
|
||||||
response_html += "</ul><hr><h2>Wszystkie nagłówki</h2><ul>"
|
|
||||||
|
|
||||||
for key, val in all_headers.items():
|
|
||||||
response_html += f"<li><strong>{key}:</strong> {val}</li>"
|
|
||||||
response_html += "</ul>"
|
|
||||||
|
|
||||||
return response_html
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
|
@@ -13,20 +13,34 @@
|
|||||||
<nav class="navbar navbar-expand-lg navbar-dark bg-secondary">
|
<nav class="navbar navbar-expand-lg navbar-dark bg-secondary">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="{{ url_for('index') }}">Zbiórki unitraklub.pl</a>
|
<a class="navbar-brand" href="{{ url_for('index') }}">Zbiórki unitraklub.pl</a>
|
||||||
<div class="collapse navbar-collapse">
|
|
||||||
|
<!-- Przycisk rozwijania dla urządzeń mobilnych -->
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#mainNavbar"
|
||||||
|
aria-controls="mainNavbar" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Nawigacja ukrywana na małych ekranach -->
|
||||||
|
<div class="collapse navbar-collapse" id="mainNavbar">
|
||||||
<ul class="navbar-nav ms-auto">
|
<ul class="navbar-nav ms-auto">
|
||||||
<li class="nav-item"><a class="nav-link" href="{{ url_for('index') }}">Aktualne zbiórki</a></li>
|
<li class="nav-item"><a class="nav-link" href="{{ url_for('index') }}">Aktualne zbiórki</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="{{ url_for('zbiorki_zrealizowane') }}">Zrealizowane zbiórki</a></li>
|
<li class="nav-item"><a class="nav-link" href="{{ url_for('zbiorki_zrealizowane') }}">Zrealizowane zbiórki</a></li>
|
||||||
{% if current_user.is_authenticated %}
|
{% if current_user.is_authenticated %}
|
||||||
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin_dashboard') }}">Panel Admina</a></li>
|
<li class="nav-item"><a class="nav-link" href="{{ url_for('admin_dashboard') }}">Panel Admina</a></li>
|
||||||
<li class="nav-item"><a class="nav-link" href="{{ url_for('logout') }}">Wyloguj</a></li>
|
<li class="nav-item"><a class="nav-link" href="{{ url_for('logout') }}">Wyloguj</a></li>
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
<li class="nav-item"><a class="nav-link" href="{{ url_for('login') }}">Zaloguj</a></li>
|
{% if is_ip_allowed %}
|
||||||
|
<li class="nav-item"><a class="nav-link" href="{{ url_for('login') }}">Zaloguj</a></li>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<div class="container mt-4">
|
<div class="container mt-4">
|
||||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||||
{% if messages %}
|
{% if messages %}
|
||||||
|
Reference in New Issue
Block a user