Compare commits
18 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
78700c48c5 | ||
![]() |
9193a94c0d | ||
![]() |
a35adf6101 | ||
![]() |
3069f38623 | ||
![]() |
194287aa39 | ||
![]() |
96546a3a9d | ||
![]() |
6d197eb1fe | ||
![]() |
7134de3e1f | ||
![]() |
add29fbb30 | ||
![]() |
18c34d8093 | ||
![]() |
7aa5c43c5a | ||
![]() |
7786310de3 | ||
![]() |
d91a46bf22 | ||
![]() |
153d50f875 | ||
![]() |
5e3146aa6a | ||
![]() |
404cc7a9bf | ||
![]() |
120b08efd0 | ||
![]() |
c219cd2691 |
@@ -14,4 +14,7 @@ DEFAULT_ADMIN_PASSWORD=admin123
|
||||
# Katalog wgrywanych plików
|
||||
UPLOAD_FOLDER=uploads
|
||||
|
||||
AUTHORIZED_COOKIE_VALUE=twoj_wlasny_hash
|
||||
AUTHORIZED_COOKIE_VALUE=twoj_wlasny_hash
|
||||
|
||||
# czas zycia cookie
|
||||
AUTH_COOKIE_MAX_AGE=86400
|
70
app.py
70
app.py
@@ -34,6 +34,7 @@ DEFAULT_ADMIN_PASSWORD = app.config.get('DEFAULT_ADMIN_PASSWORD', 'admin123')
|
||||
UPLOAD_FOLDER = app.config.get('UPLOAD_FOLDER', 'uploads')
|
||||
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'webp'}
|
||||
AUTHORIZED_COOKIE_VALUE = app.config.get('AUTHORIZED_COOKIE_VALUE', '80d31cdfe63539c9')
|
||||
AUTH_COOKIE_MAX_AGE = app.config.get('AUTH_COOKIE_MAX_AGE', 86400)
|
||||
|
||||
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
|
||||
|
||||
@@ -250,30 +251,52 @@ def inject_time():
|
||||
def inject_has_authorized_cookie():
|
||||
return {'has_authorized_cookie': 'authorized' in request.cookies}
|
||||
|
||||
@app.context_processor
|
||||
def inject_is_blocked():
|
||||
ip = request.access_route[0]
|
||||
return {'is_blocked': is_ip_blocked(ip)}
|
||||
|
||||
@app.before_request
|
||||
def require_system_password():
|
||||
if 'authorized' not in request.cookies \
|
||||
and request.endpoint != 'system_auth' \
|
||||
and not request.endpoint.startswith('login') \
|
||||
and request.endpoint != 'favicon':
|
||||
endpoint = request.endpoint
|
||||
|
||||
if request.endpoint == 'static_bp.serve_js':
|
||||
# Wyjątki: lib js/css zawsze przepuszczamy
|
||||
if endpoint in ('static_bp.serve_js_lib', 'static_bp.serve_css_lib'):
|
||||
return
|
||||
|
||||
ip = request.access_route[0]
|
||||
if is_ip_blocked(ip):
|
||||
abort(403)
|
||||
|
||||
if endpoint is None:
|
||||
return
|
||||
|
||||
if endpoint == 'system_auth':
|
||||
return
|
||||
|
||||
if 'authorized' not in request.cookies and not endpoint.startswith('login') and endpoint != 'favicon':
|
||||
|
||||
# Dla serve_js przepuszczamy tylko toasts.js
|
||||
if endpoint == 'static_bp.serve_js':
|
||||
requested_file = request.view_args.get("filename", "")
|
||||
if requested_file == "toasts.js":
|
||||
return
|
||||
if requested_file.endswith(".js"):
|
||||
return redirect(url_for('system_auth', next=request.url))
|
||||
else:
|
||||
return
|
||||
return
|
||||
|
||||
if request.endpoint.startswith('static_bp.'):
|
||||
# Blokujemy pozostałe static_bp
|
||||
if endpoint.startswith('static_bp.'):
|
||||
return
|
||||
|
||||
if request.path == '/':
|
||||
return redirect(url_for('system_auth'))
|
||||
else:
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
parsed = urlparse(request.url)
|
||||
fixed_url = urlunparse(parsed._replace(netloc=request.host))
|
||||
return redirect(url_for('system_auth', next=fixed_url))
|
||||
|
||||
from urllib.parse import urlparse, urlunparse
|
||||
parsed = urlparse(request.url)
|
||||
fixed_url = urlunparse(parsed._replace(netloc=request.host))
|
||||
return redirect(url_for('system_auth', next=fixed_url))
|
||||
|
||||
|
||||
@app.template_filter('filemtime')
|
||||
def file_mtime_filter(path):
|
||||
@@ -313,15 +336,6 @@ def forbidden(e):
|
||||
message="Nie masz uprawnień do wyświetlenia tej strony."
|
||||
), 403
|
||||
|
||||
@app.errorhandler(500)
|
||||
def internal_error(e):
|
||||
return render_template(
|
||||
'errors.html',
|
||||
code=500,
|
||||
title="Błąd serwera",
|
||||
message="Wystąpił nieoczekiwany błąd. Spróbuj ponownie później."
|
||||
), 500
|
||||
|
||||
@app.route('/favicon.ico')
|
||||
def favicon_ico():
|
||||
return redirect(url_for('static', filename='favicon.svg'))
|
||||
@@ -383,7 +397,8 @@ def system_auth():
|
||||
if request.form['password'] == SYSTEM_PASSWORD:
|
||||
reset_failed_attempts(ip)
|
||||
resp = redirect(next_page)
|
||||
resp.set_cookie('authorized', AUTHORIZED_COOKIE_VALUE)
|
||||
max_age = app.config.get('AUTH_COOKIE_MAX_AGE', 86400)
|
||||
resp.set_cookie('authorized', AUTHORIZED_COOKIE_VALUE, max_age=max_age)
|
||||
return resp
|
||||
else:
|
||||
register_failed_attempt(ip)
|
||||
@@ -456,10 +471,13 @@ def toggle_visibility(list_id):
|
||||
|
||||
return redirect(url_for('main_page'))
|
||||
|
||||
from sqlalchemy import func
|
||||
|
||||
@app.route('/login', methods=['GET', 'POST'])
|
||||
def login():
|
||||
if request.method == 'POST':
|
||||
user = User.query.filter_by(username=request.form['username']).first()
|
||||
username_input = request.form['username'].lower()
|
||||
user = User.query.filter(func.lower(User.username) == username_input).first()
|
||||
if user and check_password_hash(user.password_hash, request.form['password']):
|
||||
login_user(user)
|
||||
flash('Zalogowano pomyślnie', 'success')
|
||||
@@ -759,14 +777,14 @@ def delete_list(list_id):
|
||||
@login_required
|
||||
@admin_required
|
||||
def add_user():
|
||||
username = request.form['username']
|
||||
username = request.form['username'].lower()
|
||||
password = request.form['password']
|
||||
|
||||
if not username or not password:
|
||||
flash('Wypełnij wszystkie pola', 'danger')
|
||||
return redirect(url_for('list_users'))
|
||||
|
||||
if User.query.filter_by(username=username).first():
|
||||
if User.query.filter(func.lower(User.username) == username).first():
|
||||
flash('Użytkownik o takiej nazwie już istnieje', 'warning')
|
||||
return redirect(url_for('list_users'))
|
||||
|
||||
|
@@ -9,3 +9,4 @@ class Config:
|
||||
DEFAULT_ADMIN_PASSWORD = os.environ.get('DEFAULT_ADMIN_PASSWORD', 'admin123')
|
||||
UPLOAD_FOLDER = os.environ.get('UPLOAD_FOLDER', 'uploads')
|
||||
AUTHORIZED_COOKIE_VALUE = os.environ.get('AUTHORIZED_COOKIE_VALUE', 'cookievalue')
|
||||
AUTH_COOKIE_MAX_AGE = int(os.environ.get('AUTH_COOKIE_MAX_AGE', 86400))
|
@@ -13,5 +13,6 @@ services:
|
||||
- DEFAULT_ADMIN_PASSWORD=${DEFAULT_ADMIN_PASSWORD}
|
||||
- UPLOAD_FOLDER=${UPLOAD_FOLDER}
|
||||
- AUTHORIZED_COOKIE_VALUE=${AUTHORIZED_COOKIE_VALUE}
|
||||
- AUTH_COOKIE_MAX_AGE=${AUTH_COOKIE_MAX_AGE}
|
||||
volumes:
|
||||
- .:/app
|
||||
|
@@ -8,5 +8,5 @@ function showToast(message, type = 'primary') {
|
||||
toast.innerHTML = `<div class="d-flex"><div class="toast-body">${message}</div></div>`;
|
||||
|
||||
toastContainer.appendChild(toast);
|
||||
setTimeout(() => { toast.remove(); }, 4000);
|
||||
setTimeout(() => { toast.remove(); }, 2000);
|
||||
}
|
||||
|
@@ -5,10 +5,11 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{% block title %}Live Lista Zakupów{% endblock %}</title>
|
||||
<link rel="icon" type="image/svg+xml" href="{{ url_for('favicon') }}">
|
||||
{% if not is_blocked %}
|
||||
<link href="{{ url_for('static_bp.serve_css', filename='style.css') }}" rel="stylesheet">
|
||||
|
||||
<link href="{{ url_for('static_bp.serve_css_lib', filename='bootstrap.min.css') }}" rel="stylesheet">
|
||||
<link href="{{ url_for('static_bp.serve_css_lib', filename='glightbox.min.css') }}" rel="stylesheet">
|
||||
{% endif %}
|
||||
<link href="{{ url_for('static_bp.serve_css_lib', filename='bootstrap.min.css') }}" rel="stylesheet">
|
||||
</head>
|
||||
<body class="bg-dark text-white">
|
||||
|
||||
@@ -18,7 +19,7 @@
|
||||
🛒 <span class="text-warning">Lista</span> Zakupów
|
||||
</a>
|
||||
|
||||
{% if has_authorized_cookie %}
|
||||
{% if has_authorized_cookie and not is_blocked %}
|
||||
{% if current_user.is_authenticated %}
|
||||
<div class="d-flex justify-content-center align-items-center text-white small flex-wrap text-center">
|
||||
<span class="me-1">Zalogowany:</span>
|
||||
@@ -32,9 +33,9 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if not is_blocked %}
|
||||
<div class="d-flex align-items-center gap-2">
|
||||
{% if request.endpoint != 'system_auth' %}
|
||||
{% if request.endpoint and request.endpoint != 'system_auth' %}
|
||||
{% if current_user.is_authenticated and current_user.is_admin %}
|
||||
<a href="{{ url_for('admin_panel') }}" class="btn btn-outline-warning btn-sm">⚙️ Panel admina</a>
|
||||
{% endif %}
|
||||
@@ -45,6 +46,8 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
@@ -54,6 +57,8 @@
|
||||
|
||||
<div id="toast-container" class="toast-container position-fixed bottom-0 end-0 p-3"></div>
|
||||
|
||||
<script src="{{ url_for('static_bp.serve_js_lib', filename='bootstrap.bundle.min.js') }}"></script>
|
||||
{% if not is_blocked %}
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
{% with messages = get_flashed_messages(with_categories=true) %}
|
||||
@@ -69,9 +74,8 @@
|
||||
});
|
||||
</script>
|
||||
<script src="{{ url_for('static_bp.serve_js_lib', filename='glightbox.min.js') }}"></script>
|
||||
<script src="{{ url_for('static_bp.serve_js_lib', filename='bootstrap.bundle.min.js') }}"></script>
|
||||
<script src="{{ url_for('static_bp.serve_js_lib', filename='socket.io.min.js') }}"></script>
|
||||
{% if request.endpoint != 'system_auth' %}
|
||||
{% if request.endpoint != 'system_auth' %}
|
||||
<script src="{{ url_for('static_bp.serve_js', filename='functions.js') }}"></script>
|
||||
<script src="{{ url_for('static_bp.serve_js', filename='live.js') }}"></script>
|
||||
<script src="{{ url_for('static_bp.serve_js', filename='sockets.js') }}"></script>
|
||||
@@ -82,6 +86,7 @@
|
||||
selector: '.glightbox'
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
{% block scripts %}{% endblock %}
|
||||
|
||||
|
@@ -4,7 +4,6 @@
|
||||
|
||||
<div class="d-flex justify-content-between align-items-center flex-wrap mb-4">
|
||||
<h2 class="mb-2">{{ code }} — {{ title }}</h2>
|
||||
<a href="{{ url_for('main_page') }}" class="btn btn-outline-secondary">← Powrót na stronę główną</a>
|
||||
</div>
|
||||
|
||||
<div class="card bg-dark text-white">
|
||||
|
@@ -19,4 +19,4 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% endblock %}
|
@@ -25,4 +25,4 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
{% endblock %}
|
||||
{% endblock %}
|
Reference in New Issue
Block a user