ux i nowa funkcja blokady blednych logowan

This commit is contained in:
Mateusz Gruszczyński
2025-07-05 15:13:18 +02:00
parent d0b6d939c0
commit 11617755fb
4 changed files with 159 additions and 46 deletions

81
app.py
View File

@ -3,7 +3,7 @@ import secrets
import time
import mimetypes
from datetime import datetime, timedelta
from flask import Flask, render_template, redirect, url_for, request, flash, Blueprint, send_from_directory, request
from flask import Flask, render_template, redirect, url_for, request, flash, Blueprint, send_from_directory, request, abort
from markupsafe import Markup
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
@ -14,6 +14,7 @@ from PIL import Image
from werkzeug.utils import secure_filename
from werkzeug.middleware.proxy_fix import ProxyFix
from sqlalchemy import func, extract
from collections import defaultdict, deque
app = Flask(__name__)
app.config.from_object(Config)
@ -27,6 +28,10 @@ AUTHORIZED_COOKIE_VALUE = app.config.get('AUTHORIZED_COOKIE_VALUE', '80d31cdfe63
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
failed_login_attempts = defaultdict(deque)
MAX_ATTEMPTS = 10
TIME_WINDOW = 60 * 60
db = SQLAlchemy(app)
socketio = SocketIO(app)
login_manager = LoginManager(app)
@ -73,6 +78,26 @@ class Expense(db.Model):
added_at = db.Column(db.DateTime, default=datetime.utcnow)
receipt_filename = db.Column(db.String(255), nullable=True)
with app.app_context():
# Twój kod inicjalizacyjny, np. utworzenie konta admina
db.create_all()
from werkzeug.security import generate_password_hash
admin = User.query.filter_by(is_admin=True).first()
username = app.config.get('DEFAULT_ADMIN_USERNAME', 'admin')
password = app.config.get('DEFAULT_ADMIN_PASSWORD', 'admin123')
password_hash = generate_password_hash(password)
if admin:
# Aktualizacja jeśli dane się różnią
if admin.username != username or not check_password_hash(admin.password_hash, password):
admin.username = username
admin.password_hash = password_hash
db.session.commit()
else:
# Brak admina utwórz nowe konto
admin = User(username=username, password_hash=password_hash, is_admin=True)
db.session.add(admin)
db.session.commit()
@static_bp.route('/static/js/<path:filename>')
def serve_js(filename):
response = send_from_directory('static/js', filename)
@ -108,6 +133,30 @@ def get_progress(list_id):
percent = (purchased_count / total_count * 100) if total_count > 0 else 0
return purchased_count, total_count, percent
# zabezpieczenie logowani do systemy - błędne hasła
def is_ip_blocked(ip):
now = time.time()
attempts = failed_login_attempts[ip]
while attempts and now - attempts[0] > TIME_WINDOW:
attempts.popleft()
return len(attempts) >= MAX_ATTEMPTS
def register_failed_attempt(ip):
now = time.time()
attempts = failed_login_attempts[ip]
while attempts and now - attempts[0] > TIME_WINDOW:
attempts.popleft()
attempts.append(now)
def reset_failed_attempts(ip):
failed_login_attempts[ip].clear()
def attempts_remaining(ip):
attempts = failed_login_attempts[ip]
return max(0, MAX_ATTEMPTS - len(attempts))
####################################################
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
@ -158,6 +207,10 @@ def filesizeformat_filter(path):
def page_not_found(e):
return render_template('404.html'), 404
@app.errorhandler(403)
def forbidden(e):
return '403 Forbidden', 403
@app.route('/favicon.svg')
def favicon():
svg = '''
@ -202,25 +255,27 @@ def index_guest():
@app.route('/system-auth', methods=['GET', 'POST'])
def system_auth():
ip = request.remote_addr
next_page = request.args.get('next') or url_for('index_guest')
if is_ip_blocked(ip):
flash('Przekroczono limit prób logowania. Dostęp zablokowany na 1 godzinę.', 'danger')
return render_template('system_auth.html'), 403
if request.method == 'POST':
if request.form['password'] == SYSTEM_PASSWORD:
db.create_all()
if not User.query.filter_by(is_admin=True).first():
admin_user = User(
username=DEFAULT_ADMIN_USERNAME,
password_hash=generate_password_hash(DEFAULT_ADMIN_PASSWORD),
is_admin=True
)
db.session.add(admin_user)
db.session.commit()
flash(f'Utworzono konto administratora: login={DEFAULT_ADMIN_USERNAME}, hasło={DEFAULT_ADMIN_PASSWORD}')
reset_failed_attempts(ip)
resp = redirect(next_page)
resp.set_cookie('authorized', AUTHORIZED_COOKIE_VALUE)
return resp
flash('Nieprawidłowe hasło do systemu','danger')
else:
register_failed_attempt(ip)
if is_ip_blocked(ip):
flash('Przekroczono limit prób logowania. Dostęp zablokowany na 1 godzinę.', 'danger')
return render_template('system_auth.html'), 403
remaining = attempts_remaining(ip)
flash(f'Nieprawidłowe hasło do systemu. Pozostało prób: {remaining}', 'warning')
return render_template('system_auth.html')
@app.route('/archive_my_list/<int:list_id>')