adiciondo /register e verificação pgp
This commit is contained in:
parent
9d3efaadfe
commit
d159f4ec68
5 changed files with 254 additions and 15 deletions
|
|
@ -2,3 +2,4 @@ Flask
|
||||||
Flask-SQLAlchemy
|
Flask-SQLAlchemy
|
||||||
SQLAlchemy
|
SQLAlchemy
|
||||||
PyMySQL
|
PyMySQL
|
||||||
|
python-gnupg
|
||||||
|
|
|
||||||
172
src/main.py
172
src/main.py
|
|
@ -1,11 +1,16 @@
|
||||||
from flask import Flask, render_template
|
from flask import Flask, render_template, request, redirect, url_for, flash, session
|
||||||
from flask_sqlalchemy import SQLAlchemy
|
from flask_sqlalchemy import SQLAlchemy
|
||||||
from datetime import date
|
from datetime import date
|
||||||
|
import gnupg
|
||||||
|
import secrets
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://love:love@localhost:3309/lovedb'
|
app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://love:love@localhost:3309/lovedb'
|
||||||
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
|
||||||
|
app.config['SECRET_KEY'] = 'random'
|
||||||
|
|
||||||
|
gpg = gnupg.GPG()
|
||||||
|
|
||||||
db = SQLAlchemy(app)
|
db = SQLAlchemy(app)
|
||||||
|
|
||||||
|
|
@ -13,7 +18,7 @@ class User(db.Model):
|
||||||
id = db.Column(db.Integer, primary_key=True)
|
id = db.Column(db.Integer, primary_key=True)
|
||||||
|
|
||||||
username = db.Column(db.String(128), unique=True, nullable=False)
|
username = db.Column(db.String(128), unique=True, nullable=False)
|
||||||
password = db.Column(db.String(128), nullable=False)
|
pgp = db.Column(db.String(4096), nullable=False)
|
||||||
|
|
||||||
firstname = db.Column(db.String(128), nullable=False)
|
firstname = db.Column(db.String(128), nullable=False)
|
||||||
lastname = db.Column(db.String(128), nullable=False)
|
lastname = db.Column(db.String(128), nullable=False)
|
||||||
|
|
@ -47,14 +52,175 @@ class User(db.Model):
|
||||||
def home():
|
def home():
|
||||||
return render_template("index.html")
|
return render_template("index.html")
|
||||||
|
|
||||||
@app.route("/register")
|
@app.route("/register", methods=["GET", "POST"])
|
||||||
def register():
|
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")
|
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")
|
@app.route("/login")
|
||||||
def login():
|
def login():
|
||||||
return render_template("login.html")
|
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__":
|
if __name__ == "__main__":
|
||||||
with app.app_context():
|
with app.app_context():
|
||||||
db.create_all()
|
db.create_all()
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,19 @@
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='drip.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='drip.css') }}">
|
||||||
</head>
|
</head>
|
||||||
<header><h1>Dating Website</h1></header>
|
<header><h1>Dating Website</h1></header>
|
||||||
<nav><a href="/">home</a> / <a href="/register">register</a> / <a href="login">login</a></nav>
|
<nav>
|
||||||
|
|
||||||
|
<a href="{{ url_for('home') }}">Home</a>
|
||||||
|
|
||||||
|
{% if session.get('username') %}
|
||||||
|
<span>Welcome, {{ session['username'] }}!</span>
|
||||||
|
<a href="{{ url_for('logout') }}">Logout</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ url_for('login') }}">Login</a>
|
||||||
|
<a href="{{ url_for('register') }}">Register</a>
|
||||||
|
{% endif %}
|
||||||
|
</nav>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,58 @@
|
||||||
{% extends "page.html" %}
|
{% extends "page.html" %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h2>Register</h2>
|
<h2>Register</h2>
|
||||||
<p>Page text</p>
|
|
||||||
<p>Page text</p>
|
<form method="POST">
|
||||||
<p>Page text</p>
|
|
||||||
<p>Page text</p>
|
<h3>Identity</h3>
|
||||||
<p>Page text</p>
|
<input type="text" name="username" placeholder="Username" required><br>
|
||||||
<p>Page text</p>
|
<textarea name="pgp" placeholder="PGP Public Key" required></textarea><br>
|
||||||
<p>Page text</p>
|
|
||||||
<p>Page text</p>
|
<h3>Personal Info</h3>
|
||||||
<p>Page text</p>
|
<input type="text" name="firstname" placeholder="First Name" required><br>
|
||||||
<p>Page text</p>
|
<input type="text" name="lastname" placeholder="Last Name" required><br>
|
||||||
|
|
||||||
|
<select name="sex" required>
|
||||||
|
<option value="">Select Sex</option>
|
||||||
|
<option value="male">Male</option>
|
||||||
|
<option value="female">Female</option>
|
||||||
|
</select><br>
|
||||||
|
|
||||||
|
<input type="date" name="date_of_birth" required><br>
|
||||||
|
|
||||||
|
<h3>Profile</h3>
|
||||||
|
<input type="text" name="profile_picture" placeholder="Profile Picture URL" required><br>
|
||||||
|
|
||||||
|
<h3>Location</h3>
|
||||||
|
<input type="text" name="country" placeholder="Country" required><br>
|
||||||
|
<input type="text" name="city" placeholder="City"><br>
|
||||||
|
|
||||||
|
<h3>Physical Attributes</h3>
|
||||||
|
<input type="number" step="0.01" name="height" placeholder="Height (m)"><br>
|
||||||
|
<input type="number" name="weight" placeholder="Weight (kg)"><br>
|
||||||
|
<input type="text" name="race" placeholder="Race"><br>
|
||||||
|
|
||||||
|
<h3>Preferences</h3>
|
||||||
|
<input type="text" name="prefered_age_range" placeholder="Preferred Age Range (e.g. 20-30)"><br>
|
||||||
|
|
||||||
|
<h3>Contacts</h3>
|
||||||
|
<input type="text" name="xmpp" placeholder="XMPP" required><br>
|
||||||
|
<input type="email" name="email" placeholder="Email"><br>
|
||||||
|
<input type="text" name="phone" placeholder="Phone"><br><br>
|
||||||
|
|
||||||
|
<button type="submit">Register</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% with messages = get_flashed_messages() %}
|
||||||
|
{% if messages %}
|
||||||
|
<ul>
|
||||||
|
{% for message in messages %}
|
||||||
|
<li style="color:red;">{{ message }}</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
||||||
17
src/templates/verify.html
Normal file
17
src/templates/verify.html
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
{% extends "page.html" %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<h2>PGP Verification</h2>
|
||||||
|
|
||||||
|
<p>Decrypt the message below using your private key and paste the result.</p>
|
||||||
|
|
||||||
|
<textarea rows="10" cols="80" readonly>
|
||||||
|
{{ encrypted_message }}
|
||||||
|
</textarea>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ url_for('verify') }}">
|
||||||
|
<textarea name="decrypted_message" placeholder="Paste decrypted message here" required></textarea><br>
|
||||||
|
<button type="submit">Verify</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue