diff --git a/.env.local b/.env.local deleted file mode 100644 index 7f8a880..0000000 --- a/.env.local +++ /dev/null @@ -1,5 +0,0 @@ -DATABASE_URL=sqlite:///sentinelid.db -SECRET_KEY=my_very_secret_key -OPENROUTER_API_KEY=sk-your-openrouter-key -DEBUG=True -MODEL_NAME=google/gemma-3n-e2b-it:free diff --git a/app.py b/app.py index a7d72ca..0adca1f 100644 --- a/app.py +++ b/app.py @@ -8,22 +8,21 @@ def create_app(): app = Flask(__name__) app.config.from_object(config) - + # Initialize SQLAlchemy db.init_app(app) - # --- ✅ Enable CORS --- - # Allow both local development and production frontend domains + # Enable CORS CORS(app, resources={r"/*": {"origins": "*"}}) - # --- ✅ Register Blueprints --- + # Register ALL blueprints through main_blueprint app.register_blueprint(main_blueprint, url_prefix="/api") - # --- ✅ Auto-create tables only in development --- + # Auto-create tables only in dev with app.app_context(): db.create_all() - # Optional health check route + # Health check @app.route("/api/ping") def ping(): return {"message": "pong"} @@ -33,4 +32,4 @@ def ping(): if __name__ == "__main__": app = create_app() - app.run(debug=True, threaded=False,port=5000,host="0.0.0.0") + app.run(debug=True, threaded=False, port=5000, host="0.0.0.0") diff --git a/auth_utils.py b/auth_utils.py new file mode 100644 index 0000000..de24794 --- /dev/null +++ b/auth_utils.py @@ -0,0 +1,19 @@ +from werkzeug.security import generate_password_hash, check_password_hash +import jwt +from datetime import datetime, timedelta +from config import config + +SECRET_KEY = config.JWT_SECRET + +def hash_password(password: str) -> str: + return generate_password_hash(password) + +def verify_password(hashed: str, password: str) -> bool: + return check_password_hash(hashed, password) + +def create_jwt(user_id: int) -> str: + payload = { + "user_id": user_id, + "exp": datetime.utcnow() + timedelta(hours=12), + } + return jwt.encode(payload, SECRET_KEY, algorithm="HS256") diff --git a/routes/auth_routes.py b/routes/auth_routes.py index 17cd08c..46d254c 100644 --- a/routes/auth_routes.py +++ b/routes/auth_routes.py @@ -1,32 +1,61 @@ from flask import Blueprint, jsonify, request from werkzeug.security import generate_password_hash, check_password_hash from models import db, User +import jwt +from datetime import datetime, timedelta +from config import config auth_bp = Blueprint("auth", __name__) +# Generate JWT token +def create_jwt(user_id): + payload = { + "user_id": user_id, + "exp": datetime.utcnow() + timedelta(hours=12) + } + return jwt.encode(payload, config.SECRET_KEY, algorithm="HS256") + + @auth_bp.route("/register", methods=["POST"]) def register(): data = request.get_json() + + # Validate required fields if not data or not all(k in data for k in ("username", "email", "password")): return jsonify({"error": "username, email, and password are required"}), 400 + # Check existing user if User.query.filter_by(email=data["email"]).first(): return jsonify({"error": "User with this email already exists"}), 400 + # Create user pw_hash = generate_password_hash(data["password"], method="pbkdf2:sha256", salt_length=16) user = User(username=data["username"], email=data["email"], password_hash=pw_hash) + db.session.add(user) db.session.commit() + return jsonify({"message": "User registered!", "user_id": user.id}), 201 + @auth_bp.route("/login", methods=["POST"]) def login(): data = request.get_json() + + # Validate fields if not data or not all(k in data for k in ("email", "password")): return jsonify({"error": "Email and password are required"}), 400 user = User.query.filter_by(email=data["email"]).first() + if not user or not check_password_hash(user.password_hash, data["password"]): return jsonify({"error": "Invalid email or password"}), 401 - return jsonify({"message": "Login successful!", "user_id": user.id}), 200 + # Create JWT token + token = create_jwt(user.id) + + return jsonify({ + "message": "Login successful!", + "token": token, + "user_id": user.id + }), 200