mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2025-11-18 03:26:17 +00:00
Update flask_server.py
This commit is contained in:
@@ -88,6 +88,210 @@ def require_auth(f):
|
||||
|
||||
return decorated_function
|
||||
|
||||
# Authentication endpoints
|
||||
@app.route('/api/auth/status', methods=['GET'])
|
||||
def auth_status():
|
||||
"""Check if authentication is enabled and if current session is valid"""
|
||||
try:
|
||||
auth_config = load_auth_config()
|
||||
is_enabled = auth_config.get("auth_enabled", False)
|
||||
|
||||
# Check if user has valid token
|
||||
is_authenticated = False
|
||||
if is_enabled:
|
||||
auth_header = request.headers.get('Authorization')
|
||||
if auth_header and auth_header.startswith('Bearer '):
|
||||
token = auth_header.split(' ')[1]
|
||||
try:
|
||||
payload = jwt.decode(token, JWT_SECRET, algorithms=['HS256'])
|
||||
if time.time() <= payload.get('exp', 0):
|
||||
is_authenticated = True
|
||||
except:
|
||||
pass
|
||||
|
||||
return jsonify({
|
||||
"auth_enabled": is_enabled,
|
||||
"authenticated": is_authenticated or not is_enabled
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@app.route('/api/auth/setup', methods=['POST'])
|
||||
def auth_setup():
|
||||
"""Setup authentication for the first time"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
username = data.get('username', '').strip()
|
||||
password = data.get('password', '').strip()
|
||||
|
||||
if not username or not password:
|
||||
return jsonify({"error": "Username and password are required"}), 400
|
||||
|
||||
if len(password) < 6:
|
||||
return jsonify({"error": "Password must be at least 6 characters"}), 400
|
||||
|
||||
# Hash password and save config
|
||||
password_hash = hash_password(password)
|
||||
|
||||
auth_config = {
|
||||
"auth_enabled": True,
|
||||
"username": username,
|
||||
"password_hash": password_hash,
|
||||
"created_at": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
save_auth_config(auth_config)
|
||||
|
||||
# Generate JWT token
|
||||
token = jwt.encode({
|
||||
'username': username,
|
||||
'exp': time.time() + SESSION_TIMEOUT
|
||||
}, JWT_SECRET, algorithm='HS256')
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"token": token
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@app.route('/api/auth/skip', methods=['POST'])
|
||||
def auth_skip():
|
||||
"""Skip authentication setup"""
|
||||
try:
|
||||
auth_config = {
|
||||
"auth_enabled": False,
|
||||
"skipped": True,
|
||||
"skipped_at": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
save_auth_config(auth_config)
|
||||
|
||||
return jsonify({"success": True})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@app.route('/api/auth/login', methods=['POST'])
|
||||
def auth_login():
|
||||
"""Login with username and password"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
username = data.get('username', '').strip()
|
||||
password = data.get('password', '').strip()
|
||||
|
||||
if not username or not password:
|
||||
return jsonify({"error": "Username and password are required"}), 400
|
||||
|
||||
# Load auth config
|
||||
auth_config = load_auth_config()
|
||||
|
||||
if not auth_config.get("auth_enabled", False):
|
||||
return jsonify({"error": "Authentication is not enabled"}), 400
|
||||
|
||||
# Verify credentials
|
||||
stored_username = auth_config.get("username", "")
|
||||
stored_password_hash = auth_config.get("password_hash", "")
|
||||
|
||||
if username != stored_username or hash_password(password) != stored_password_hash:
|
||||
return jsonify({"error": "Invalid username or password"}), 401
|
||||
|
||||
# Generate JWT token
|
||||
token = jwt.encode({
|
||||
'username': username,
|
||||
'exp': time.time() + SESSION_TIMEOUT
|
||||
}, JWT_SECRET, algorithm='HS256')
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"token": token
|
||||
})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@app.route('/api/auth/refresh', methods=['POST'])
|
||||
def auth_refresh():
|
||||
"""Refresh JWT token"""
|
||||
try:
|
||||
auth_header = request.headers.get('Authorization')
|
||||
if not auth_header or not auth_header.startswith('Bearer '):
|
||||
return jsonify({"error": "No token provided"}), 401
|
||||
|
||||
token = auth_header.split(' ')[1]
|
||||
|
||||
try:
|
||||
# Verify current token
|
||||
payload = jwt.decode(token, JWT_SECRET, algorithms=['HS256'])
|
||||
username = payload.get('username')
|
||||
|
||||
# Generate new token
|
||||
new_token = jwt.encode({
|
||||
'username': username,
|
||||
'exp': time.time() + SESSION_TIMEOUT
|
||||
}, JWT_SECRET, algorithm='HS256')
|
||||
|
||||
return jsonify({
|
||||
"success": True,
|
||||
"token": new_token
|
||||
})
|
||||
except jwt.InvalidTokenError:
|
||||
return jsonify({"error": "Invalid token"}), 401
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@app.route('/api/auth/logout', methods=['POST'])
|
||||
@require_auth
|
||||
def auth_logout():
|
||||
"""Logout (client should delete token)"""
|
||||
return jsonify({"success": True})
|
||||
|
||||
@app.route('/api/auth/disable', methods=['POST'])
|
||||
@require_auth
|
||||
def auth_disable():
|
||||
"""Disable authentication"""
|
||||
try:
|
||||
auth_config = {
|
||||
"auth_enabled": False,
|
||||
"disabled_at": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
save_auth_config(auth_config)
|
||||
|
||||
return jsonify({"success": True})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
@app.route('/api/auth/change-password', methods=['POST'])
|
||||
@require_auth
|
||||
def auth_change_password():
|
||||
"""Change password"""
|
||||
try:
|
||||
data = request.get_json()
|
||||
current_password = data.get('current_password', '').strip()
|
||||
new_password = data.get('new_password', '').strip()
|
||||
|
||||
if not current_password or not new_password:
|
||||
return jsonify({"error": "Current and new password are required"}), 400
|
||||
|
||||
if len(new_password) < 6:
|
||||
return jsonify({"error": "New password must be at least 6 characters"}), 400
|
||||
|
||||
# Load auth config
|
||||
auth_config = load_auth_config()
|
||||
|
||||
# Verify current password
|
||||
stored_password_hash = auth_config.get("password_hash", "")
|
||||
if hash_password(current_password) != stored_password_hash:
|
||||
return jsonify({"error": "Current password is incorrect"}), 401
|
||||
|
||||
# Update password
|
||||
auth_config["password_hash"] = hash_password(new_password)
|
||||
auth_config["updated_at"] = datetime.now().isoformat()
|
||||
|
||||
save_auth_config(auth_config)
|
||||
|
||||
return jsonify({"success": True})
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
|
||||
app = Flask(__name__)
|
||||
CORS(app) # Enable CORS for Next.js frontend
|
||||
|
||||
Reference in New Issue
Block a user