from flask import Flask, render_template, request, redirect, url_for, flash, session from flask_sqlalchemy import SQLAlchemy from datetime import date import gnupg import secrets app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://love:love@localhost:3309/lovedb' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False app.config['SECRET_KEY'] = 'random' gpg = gnupg.GPG() db = SQLAlchemy(app) class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(128), unique=True, nullable=False) pgp = db.Column(db.String(4096), nullable=False) firstname = db.Column(db.String(128), nullable=False) lastname = db.Column(db.String(128), nullable=False) sex = db.Column(db.Enum('male', 'female'), nullable=False) date_of_birth = db.Column(db.Date, nullable=False) profile_picture = db.Column(db.String(200), nullable=False) pictures = db.Column(db.JSON, nullable=True) country = db.Column(db.String(128), nullable=False) city = db.Column(db.String(128), nullable=True) height = db.Column(db.Float, nullable=True) weight = db.Column(db.Integer, nullable=True) race = db.Column(db.String(20), nullable=True) prefered_age_range = db.Column(db.String(20), nullable=True) likes = db.Column(db.JSON, nullable=True) dislikes = db.Column(db.JSON, nullable=True) xmpp = db.Column(db.String(128), unique=True, nullable=False) email = db.Column(db.String(128), unique=True, nullable=True) phone = db.Column(db.String(20), unique=True, nullable=True) is_verified = db.Column(db.Boolean, default=False) @app.route("/") def home(): return render_template("index.html") @app.route("/register", methods=["GET", "POST"]) def register(): if request.method == "POST": username = request.form.get("username") pgp = request.form.get("pgp") firstname = request.form.get("firstname") lastname = request.form.get("lastname") sex = request.form.get("sex") date_of_birth = request.form.get("date_of_birth") profile_picture = request.form.get("profile_picture") country = request.form.get("country") xmpp = request.form.get("xmpp") email = request.form.get("email") phone = request.form.get("phone") city = request.form.get("city") height = request.form.get("height") weight = request.form.get("weight") race = request.form.get("race") prefered_age_range = request.form.get("prefered_age_range") if not all([username, pgp, firstname, lastname, sex, date_of_birth, profile_picture, country, xmpp]): flash("Please fill all required fields.") return redirect(url_for("register")) if User.query.filter_by(username=username).first(): flash("Username already exists.") return redirect(url_for("register")) if User.query.filter_by(xmpp=xmpp).first(): flash("XMPP already exists.") return redirect(url_for("register")) if email and User.query.filter_by(email=email).first(): flash("Email already exists.") return redirect(url_for("register")) if phone and User.query.filter_by(phone=phone).first(): flash("Phone already exists.") return redirect(url_for("register")) try: dob = date.fromisoformat(date_of_birth) except ValueError: flash("Invalid date format.") return redirect(url_for("register")) today = date.today() age = today.year - dob.year - ((today.month, today.day) < (dob.month, dob.day)) if age < 18: flash("You must be at least 18 years old to register.") return redirect(url_for("register")) session["pending_user"] = { "username": username, "pgp": pgp, "firstname": firstname, "lastname": lastname, "sex": sex, "date_of_birth": date_of_birth, "profile_picture": profile_picture, "country": country, "xmpp": xmpp, "email": email, "phone": phone, "city": city, "height": height, "weight": weight, "race": race, "prefered_age_range": prefered_age_range } import_result = gpg.import_keys(pgp) if not import_result.fingerprints: flash("Invalid PGP key. Make sure you pasted the full ASCII-armored public key.") return redirect(url_for("register")) fingerprint = import_result.fingerprints[0] random_string = secrets.token_hex(16) challenge_phrase = f"this is the unencrypted string: {random_string}" encrypted_data = gpg.encrypt( challenge_phrase, recipients=[fingerprint] ) if not encrypted_data.ok: flash("Failed to encrypt challenge. Check your PGP key.") return redirect(url_for("register")) session["pgp_expected_phrase"] = challenge_phrase return render_template( "verify.html", encrypted_message=str(encrypted_data) ) return render_template("register.html") @app.route("/verify", methods=["POST"]) def verify(): expected_phrase = session.get("pgp_expected_phrase") data = session.get("pending_user") if not expected_phrase or not data: flash("Verification session expired.") return redirect(url_for("register")) submitted = request.form.get("decrypted_message") if not submitted: flash("You must paste the decrypted message.") return redirect(url_for("register")) if submitted.strip() != expected_phrase: flash("Verification failed.") return redirect(url_for("register")) dob = date.fromisoformat(data["date_of_birth"]) new_user = User( username=data["username"], pgp=data["pgp"], firstname=data["firstname"], lastname=data["lastname"], sex=data["sex"], date_of_birth=dob, profile_picture=data["profile_picture"], country=data["country"], xmpp=data["xmpp"], email=data["email"] or None, phone=data["phone"] or None, city=data["city"] or None, height=float(data["height"]) if data["height"] else None, weight=int(data["weight"]) if data["weight"] else None, race=data["race"] or None, prefered_age_range=data["prefered_age_range"] or None, is_verified=True ) db.session.add(new_user) db.session.commit() # Clear session session.pop("pending_user", None) session.pop("pgp_expected_phrase", None) flash("PGP verification successful!") session['user_id'] = user.id session['username'] = user.username return redirect(url_for("login")) @app.route("/login") def login(): return render_template("login.html") @app.route("/logout") def logout(): session.pop('user_id', None) session.pop('username', None) flash("Logged out successfully") return redirect(url_for("home")) if __name__ == "__main__": with app.app_context(): db.create_all() app.run(debug=True)