Add csrf extempts

parent 855f0860
......@@ -5,13 +5,14 @@ from flask_login import login_user, logout_user, login_required, current_user
from flask_jwt_extended import create_access_token, jwt_required, get_jwt_identity, get_jwt
from werkzeug.security import check_password_hash
from app.auth import bp
from app import db
from app import db, csrf
from app.auth.forms import LoginForm, RegistrationForm
from app.utils.security import validate_password_strength, generate_secure_token, rate_limit_check
from app.utils.logging import log_security_event
logger = logging.getLogger(__name__)
@csrf.exempt
@bp.route('/login', methods=['GET', 'POST'])
def login():
"""User login endpoint"""
......@@ -67,6 +68,7 @@ def login():
return render_template('auth/login.html', form=form)
@csrf.exempt
@bp.route('/logout')
@login_required
def logout():
......@@ -87,6 +89,7 @@ def logout():
flash('You have been logged out successfully.', 'info')
return redirect(url_for('auth.login'))
@csrf.exempt
@bp.route('/register', methods=['GET', 'POST'])
def register():
"""User registration endpoint (disabled by default, configurable by admin)"""
......@@ -143,6 +146,7 @@ def register():
return render_template('auth/register.html', form=form)
@csrf.exempt
@bp.route('/api/login', methods=['POST'])
def api_login():
"""API login endpoint for JWT authentication"""
......@@ -199,6 +203,7 @@ def api_login():
logger.error(f"API login error: {str(e)}")
return jsonify({'error': 'Internal server error'}), 500
@csrf.exempt
@bp.route('/api/logout', methods=['POST'])
@jwt_required()
def api_logout():
......@@ -228,6 +233,7 @@ def api_logout():
logger.error(f"API logout error: {str(e)}")
return jsonify({'error': 'Internal server error'}), 500
@csrf.exempt
@bp.route('/api/refresh', methods=['POST'])
@jwt_required()
def api_refresh():
......@@ -255,6 +261,7 @@ def api_refresh():
logger.error(f"Token refresh error: {str(e)}")
return jsonify({'error': 'Internal server error'}), 500
@csrf.exempt
@bp.route('/api/profile', methods=['GET'])
@jwt_required()
def api_profile():
......@@ -273,6 +280,7 @@ def api_profile():
logger.error(f"Profile fetch error: {str(e)}")
return jsonify({'error': 'Internal server error'}), 500
@csrf.exempt
@bp.route('/api/change-password', methods=['POST'])
@jwt_required()
def api_change_password():
......@@ -313,6 +321,7 @@ def api_change_password():
logger.error(f"Password change error: {str(e)}")
return jsonify({'error': 'Internal server error'}), 500
@csrf.exempt
@bp.route('/api/sessions', methods=['GET'])
@jwt_required()
def api_user_sessions():
......@@ -333,6 +342,7 @@ def api_user_sessions():
logger.error(f"Sessions fetch error: {str(e)}")
return jsonify({'error': 'Internal server error'}), 500
@csrf.exempt
@bp.route('/api/sessions/<session_id>', methods=['DELETE'])
@jwt_required()
def api_terminate_session(session_id):
......
......@@ -4,13 +4,14 @@ from datetime import datetime
from flask import render_template, request, jsonify, redirect, url_for, flash, current_app
from flask_login import login_required, current_user
from app.main import bp
from app import db
from app import db, csrf
from app.upload.file_handler import get_file_upload_handler
from app.upload.fixture_parser import get_fixture_parser
from app.utils.security import require_admin, require_active_user
logger = logging.getLogger(__name__)
@csrf.exempt
@bp.route('/')
def index():
"""Home page"""
......@@ -40,6 +41,7 @@ def index():
return redirect(url_for('main.dashboard'))
return render_template('main/index.html')
@csrf.exempt
@bp.route('/dashboard')
@login_required
@require_active_user
......@@ -94,6 +96,7 @@ def dashboard():
flash('Error loading dashboard', 'error')
return render_template('main/dashboard.html')
@csrf.exempt
@bp.route('/fixtures')
@login_required
@require_active_user
......@@ -181,6 +184,7 @@ def fixtures():
return render_template('main/matches.html', fixtures=[], pagination=None)
# Keep the old /matches route for backward compatibility
@csrf.exempt
@bp.route('/matches')
@login_required
@require_active_user
......@@ -188,6 +192,7 @@ def matches():
"""Redirect to fixtures for backward compatibility"""
return redirect(url_for('main.fixtures'))
@csrf.exempt
@bp.route('/fixture/<fixture_id>')
@login_required
@require_active_user
......@@ -230,6 +235,7 @@ def fixture_detail(fixture_id):
flash('Error loading fixture details', 'error')
return redirect(url_for('main.matches'))
@csrf.exempt
@bp.route('/fixture/<fixture_id>/delete', methods=['POST'])
@login_required
@require_active_user
......@@ -290,6 +296,7 @@ def delete_fixture(fixture_id):
flash('Error deleting fixture', 'error')
return redirect(url_for('main.matches'))
@csrf.exempt
@bp.route('/match/<int:id>')
@login_required
@require_active_user
......@@ -318,6 +325,7 @@ def match_detail(id):
flash('Error loading match details', 'error')
return redirect(url_for('main.fixture_detail', fixture_id=request.args.get('fixture_id', '')))
@csrf.exempt
@bp.route('/match/<int:match_id>/outcomes', methods=['POST'])
@login_required
@require_active_user
......@@ -386,6 +394,7 @@ def update_match_outcomes(match_id):
logger.error(f"Update match outcomes error: {str(e)}")
return jsonify({'error': 'Failed to update outcomes'}), 500
@csrf.exempt
@bp.route('/match/<int:match_id>/outcomes/<int:outcome_id>', methods=['DELETE'])
@login_required
@require_active_user
......@@ -424,6 +433,7 @@ def delete_match_outcome(match_id, outcome_id):
logger.error(f"Delete match outcome error: {str(e)}")
return jsonify({'error': 'Failed to delete outcome'}), 500
@csrf.exempt
@bp.route('/uploads')
@login_required
@require_active_user
......@@ -467,6 +477,7 @@ def uploads():
flash('Error loading uploads', 'error')
return render_template('main/uploads.html', uploads=[], pagination=None)
@csrf.exempt
@bp.route('/statistics')
@login_required
@require_active_user
......@@ -511,6 +522,7 @@ def statistics():
flash('Error loading statistics', 'error')
return render_template('main/statistics.html')
@csrf.exempt
@bp.route('/admin')
@login_required
@require_admin
......@@ -553,6 +565,7 @@ def admin_panel():
flash('Error loading admin panel', 'error')
return render_template('main/admin.html')
@csrf.exempt
@bp.route('/admin/users')
@login_required
@require_admin
......@@ -603,6 +616,7 @@ def admin_users():
flash('Error loading users', 'error')
return render_template('main/admin_users.html', users=[], pagination=None)
@csrf.exempt
@bp.route('/admin/logs')
@login_required
@require_admin
......@@ -647,6 +661,7 @@ def admin_logs():
flash('Error loading logs', 'error')
return render_template('main/admin_logs.html', logs=[], pagination=None)
@csrf.exempt
@bp.route('/admin/users/<int:user_id>/edit', methods=['POST'])
@login_required
@require_admin
......@@ -695,6 +710,7 @@ def admin_edit_user(user_id):
logger.error(f"Admin edit user error: {str(e)}")
return jsonify({'error': 'Failed to update user'}), 500
@csrf.exempt
@bp.route('/admin/users/<int:user_id>/delete', methods=['DELETE'])
@login_required
@require_admin
......@@ -719,6 +735,7 @@ def admin_delete_user(user_id):
logger.error(f"Admin delete user error: {str(e)}")
return jsonify({'error': 'Failed to delete user'}), 500
@csrf.exempt
@bp.route('/admin/users/create', methods=['POST'])
@login_required
@require_admin
......@@ -768,6 +785,7 @@ def admin_create_user():
logger.error(f"Admin create user error: {str(e)}")
return jsonify({'error': 'Failed to create user'}), 500
@csrf.exempt
@bp.route('/admin/users/<int:user_id>/reset-password', methods=['POST'])
@login_required
@require_admin
......@@ -797,6 +815,7 @@ def admin_reset_user_password(user_id):
logger.error(f"Admin reset password error: {str(e)}")
return jsonify({'error': 'Failed to reset password'}), 500
@csrf.exempt
@bp.route('/admin/settings')
@login_required
@require_admin
......@@ -819,6 +838,7 @@ def admin_system_settings():
flash('Error loading system settings', 'error')
return render_template('main/admin_settings.html', settings={})
@csrf.exempt
@bp.route('/admin/settings/registration', methods=['GET', 'POST'])
@login_required
@require_admin
......@@ -853,6 +873,7 @@ def admin_registration_settings():
logger.error(f"Admin registration settings error: {str(e)}")
return jsonify({'error': 'Failed to update registration settings'}), 500
@csrf.exempt
@bp.route('/admin/settings/<setting_key>', methods=['GET', 'POST'])
@login_required
@require_admin
......@@ -909,6 +930,7 @@ def admin_setting_detail(setting_key):
logger.error(f"Admin setting detail error: {str(e)}")
return jsonify({'error': 'Failed to update setting'}), 500
@csrf.exempt
@bp.route('/admin/database/migrations')
@login_required
@require_admin
......@@ -926,6 +948,7 @@ def admin_database_migrations():
flash('Error loading migration status', 'error')
return render_template('main/admin_migrations.html', migration_status={})
@csrf.exempt
@bp.route('/admin/database/migrations/run', methods=['POST'])
@login_required
@require_admin
......@@ -965,6 +988,7 @@ def admin_run_migrations():
'message': f'Failed to run migrations: {str(e)}'
}), 500
@csrf.exempt
@bp.route('/admin/database/migrations/status')
@login_required
@require_admin
......@@ -986,6 +1010,7 @@ def admin_migration_status():
'message': f'Failed to get migration status: {str(e)}'
}), 500
@csrf.exempt
@bp.route('/health')
def health_check():
"""Health check endpoint"""
......@@ -1016,6 +1041,7 @@ def health_check():
'timestamp': db.func.now()
}), 503
@csrf.exempt
@bp.route('/api/dashboard-data')
@login_required
@require_active_user
......@@ -1054,6 +1080,7 @@ def api_dashboard_data():
# API Token Management Routes
@csrf.exempt
@bp.route('/profile/tokens')
@login_required
@require_active_user
......@@ -1073,6 +1100,7 @@ def user_tokens():
flash('Error loading API tokens', 'error')
return render_template('main/user_tokens.html', tokens=[])
@csrf.exempt
@bp.route('/profile/tokens/create', methods=['POST'])
@login_required
@require_active_user
......@@ -1111,6 +1139,7 @@ def create_api_token():
logger.error(f"Create API token error: {str(e)}")
return jsonify({'error': 'Failed to create API token'}), 500
@csrf.exempt
@bp.route('/profile/tokens/<int:token_id>/delete', methods=['DELETE'])
@login_required
@require_active_user
......@@ -1139,6 +1168,7 @@ def delete_api_token(token_id):
logger.error(f"Delete API token error: {str(e)}")
return jsonify({'error': 'Failed to delete API token'}), 500
@csrf.exempt
@bp.route('/profile/tokens/<int:token_id>/revoke', methods=['POST'])
@login_required
@require_active_user
......@@ -1169,6 +1199,7 @@ def revoke_api_token(token_id):
logger.error(f"Revoke API token error: {str(e)}")
return jsonify({'error': 'Failed to revoke API token'}), 500
@csrf.exempt
@bp.route('/profile/tokens/<int:token_id>/extend', methods=['POST'])
@login_required
@require_active_user
......@@ -1205,6 +1236,7 @@ def extend_api_token(token_id):
# API Routes with Token Authentication
@csrf.exempt
@bp.route('/api/matches')
def api_matches():
"""API endpoint to list matches (requires API token)"""
......@@ -1260,6 +1292,7 @@ def api_matches():
return _api_matches()
@csrf.exempt
@bp.route('/api/fixtures')
def api_fixtures():
"""API endpoint to list fixtures (requires API token)"""
......@@ -1313,6 +1346,7 @@ def api_fixtures():
return _api_fixtures()
@csrf.exempt
@bp.route('/api/match/<int:match_id>')
def api_match_detail(match_id):
"""API endpoint to get match details (requires API token)"""
......@@ -1342,6 +1376,7 @@ def api_match_detail(match_id):
return _api_match_detail()
@csrf.exempt
@bp.route('/download/zip/<int:match_id>')
@login_required
@require_active_user
......
......@@ -16,6 +16,7 @@ from app.upload.forms import FixtureUploadForm, ZipUploadForm
logger = logging.getLogger(__name__)
@csrf.exempt
@bp.route('/fixture', methods=['GET', 'POST'])
@login_required
@require_active_user
......@@ -68,6 +69,7 @@ def upload_fixture():
return render_template('upload/fixture.html', form=form)
@csrf.exempt
@bp.route('/zip', methods=['POST'])
@login_required
@require_active_user
......@@ -131,6 +133,7 @@ def upload_zip():
flash('Upload processing failed', 'error')
return redirect(request.referrer or url_for('main.fixtures'))
@csrf.exempt
@bp.route('/zip/<int:match_id>', methods=['GET', 'POST'])
@login_required
@require_active_user
......@@ -191,6 +194,7 @@ def upload_zip_page(match_id):
return render_template('upload/zip.html', form=form, match=match)
@csrf.exempt
@bp.route('/zip/<int:match_id>/delete', methods=['POST'])
@login_required
@require_active_user
......@@ -842,6 +846,7 @@ def api_upload_info(upload_id):
logger.error(f"Upload info error: {str(e)}")
return jsonify({'error': 'Failed to get upload info'}), 500
@csrf.exempt
@bp.route('/fixture/<fixture_id>/zip', methods=['POST'])
@login_required
@require_active_user
......@@ -915,8 +920,8 @@ def upload_fixture_zip(fixture_id):
flash('Upload processing failed', 'error')
return redirect(request.referrer or url_for('main.fixtures'))
@bp.route('/chunk', methods=['POST'])
@csrf.exempt
@bp.route('/chunk', methods=['POST'])
@login_required
@require_active_user
def upload_chunk():
......@@ -956,8 +961,8 @@ def upload_chunk():
logger.error(f"Chunk upload error: {str(e)}")
return jsonify({'success': False, 'error': str(e)}), 500
@bp.route('/finalize', methods=['POST'])
@csrf.exempt
@bp.route('/finalize', methods=['POST'])
@login_required
@require_active_user
def finalize_upload():
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment