app.py (After DSC Security Review)
0 ISSUES
1 import os
2 from flask import Flask, request, jsonify
3 from flask_cors import CORS
4 from flask_limiter import Limiter
5 from dotenv import load_dotenv # Secrets from .env file
6 from werkzeug.security import generate_password_hash, check_password_hash
7 from functools import wraps
8 from marshmallow import Schema, fields, validate # Input validation
9
10 load_dotenv()
11 app = Flask(__name__)
12 app.config['SECRET_KEY'] = os.environ['SECRET_KEY'] # From environment
13 CORS(app, origins=os.environ.get('ALLOWED_ORIGINS','').split(','))
14 limiter = Limiter(app, default_limits=["60/minute"])
15
16 def require_auth(f): # JWT/token auth decorator
17 @wraps(f)
18 def decorated(*args, **kwargs):
19 token = request.headers.get('Authorization')
20 if not token or not verify_token(token):
21 return jsonify({"error": "Unauthorised"}), 401
22 return f(*args, **kwargs)
23 return decorated
24
25 @app.route('/api/search')
26 @limiter.limit("30/minute")
27 def search():
28 try:
29 query = request.args.get('q', '').strip()[:100] # Sanitised + length limit
30 conn = get_db()
31 results = conn.execute(
32 "SELECT id, name, company FROM customers WHERE name LIKE ?", # Parameterised
33 (f"%{query}%",)
34 )
35 return jsonify([dict(r) for r in results])
36 except Exception as e:
37 app.logger.error(f"Search error: {e}")
38 return jsonify({"error": "Search failed"}), 500