email confirmations
parent
31b82cdd30
commit
3ffbbce551
35
app.py
35
app.py
|
@ -84,8 +84,13 @@ def register():
|
|||
team_elig = "team_eligibility" in request.form
|
||||
affiliation = request.form["affiliation"]
|
||||
team_key = utils.generate_team_key()
|
||||
team = Team.create(name=team_name, email=team_email, eligible=team_elig, affiliation=affiliation, key=team_key)
|
||||
confirmation_key = utils.generate_confirmation_key()
|
||||
team = Team.create(name=team_name, email=team_email, eligible=team_elig, affiliation=affiliation, key=team_key,
|
||||
email_confirmation_key=confirmation_key)
|
||||
TeamAccess.create(team=team, ip=utils.get_ip(), time=datetime.now())
|
||||
|
||||
utils.send_confirmation_email(team_email, confirmation_key, team_key)
|
||||
|
||||
session["team_id"] = team.id
|
||||
flash("Team created.")
|
||||
return redirect(url_for('dashboard'))
|
||||
|
@ -107,6 +112,17 @@ def assign_random():
|
|||
|
||||
# Things that require a team
|
||||
|
||||
@app.route('/confirm_email/', methods=["POST"])
|
||||
@utils.login_required
|
||||
def confirm_email():
|
||||
if request.form["confirmation_key"] == g.team.email_confirmation_key:
|
||||
flash("Email confirmed!")
|
||||
g.team.email_confirmed = True
|
||||
g.team.save()
|
||||
else:
|
||||
flash("Incorrect confirmation key.")
|
||||
return redirect(url_for('dashboard'))
|
||||
|
||||
@app.route('/team/', methods=["GET", "POST"])
|
||||
@utils.login_required
|
||||
def dashboard():
|
||||
|
@ -125,17 +141,28 @@ def dashboard():
|
|||
team_email = request.form["team_email"]
|
||||
affiliation = request.form["affiliation"]
|
||||
team_elig = "team_eligibility" in request.form
|
||||
|
||||
email_changed = (team_email != g.team.email)
|
||||
|
||||
g.team.name = team_name
|
||||
g.team.email = team_email
|
||||
g.team.affiliation = affiliation
|
||||
g.team.eligible = team_elig
|
||||
if email_changed:
|
||||
g.team.email_confirmation_key = utils.generate_confirmation_key()
|
||||
g.team.email_confirmed = False
|
||||
utils.send_confirmation_email(team_email, g.team.email_confirmation_key, g.team.key)
|
||||
flash("Changes saved. Please check your email for a new confirmation key.")
|
||||
else:
|
||||
flash("Changes saved.")
|
||||
g.team.save()
|
||||
flash("Changes saved.")
|
||||
|
||||
|
||||
return redirect(url_for('dashboard'))
|
||||
|
||||
@app.route('/challenges/')
|
||||
@utils.competition_running_required
|
||||
@utils.login_required
|
||||
@utils.confirmed_email_required
|
||||
def challenges():
|
||||
chals = Challenge.select().order_by(Challenge.points)
|
||||
solved = Challenge.select().join(ChallengeSolve).where(ChallengeSolve.team == g.team)
|
||||
|
@ -143,7 +170,7 @@ def challenges():
|
|||
|
||||
@app.route('/submit/<int:challenge>/', methods=["POST"])
|
||||
@utils.competition_running_required
|
||||
@utils.login_required
|
||||
@utils.confirmed_email_required
|
||||
def submit(challenge):
|
||||
chal = Challenge.get(Challenge.id == challenge)
|
||||
flag = request.form["flag"]
|
||||
|
|
|
@ -6,6 +6,7 @@ cdn = True
|
|||
proxied_ip_header = "X-Forwarded-For"
|
||||
flag_rl = 10
|
||||
teams_on_graph = 10
|
||||
mail_from = "tjctf@sandbox1431.mailgun.org"
|
||||
|
||||
# Don't touch these. Instead, copy secrets.example to secrets and edit that.
|
||||
import yaml
|
||||
|
|
2
ctftool
2
ctftool
|
@ -37,7 +37,7 @@ elif operation == "gen-team":
|
|||
diff = timedelta(minutes=5)
|
||||
for i in range(n):
|
||||
name = "Team {}".format(i + 1)
|
||||
t = Team.create(name=name, email="none@none.com", affiliation="Autogenerated", eligible=True, key="")
|
||||
t = Team.create(name=name, email="none@none.com", affiliation="Autogenerated", eligible=True, key="", email_confirmation_key="autogen", email_confirmed=True)
|
||||
t.key = "autogen{}".format(t.id)
|
||||
t.save()
|
||||
print("Team added with id {}".format(t.id))
|
||||
|
|
|
@ -11,6 +11,8 @@ class Team(BaseModel):
|
|||
affiliation = CharField()
|
||||
eligible = BooleanField()
|
||||
first_login = BooleanField(default=True)
|
||||
email_confirmed = BooleanField(default=False)
|
||||
email_confirmation_key = CharField()
|
||||
key = CharField()
|
||||
|
||||
def solved(self, challenge):
|
||||
|
|
|
@ -44,6 +44,26 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% if not team.email_confirmed %}
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<div class="card red darken-2">
|
||||
<div class="card-content white-text">
|
||||
<span class="card-title">Email unconfirmed</span>
|
||||
<p>It looks like you haven't confirmed your email yet. Check the email you used for registration;
|
||||
the system should have sent you an email confirmation key. Paste it below:</p>
|
||||
<form action="{{ url_for('confirm_email') }}" method="POST">
|
||||
<div class="input-field">
|
||||
<label for="confirmation-key" class="white-text">Confirmation key</label>
|
||||
<input required id="confirmation-key" name="confirmation_key" type="text" />
|
||||
</div>
|
||||
<button class="btn waves-effect waves-light" type="submit">Confirm email</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<h4>Team information</h4>
|
||||
<p>Your score is currently {{ team_score }}. <a href="{{ url_for('challenges') }}">Go solve more challenges!</a></p>
|
||||
<p>Your team email is <code>{{ team.email }}</code>, and you are affiliated with
|
||||
|
|
33
utils.py
33
utils.py
|
@ -1,6 +1,7 @@
|
|||
import random
|
||||
import config
|
||||
import json
|
||||
import requests
|
||||
from datetime import datetime
|
||||
from functools import wraps
|
||||
from flask import request, session, redirect, url_for, flash, g
|
||||
|
@ -14,6 +15,9 @@ def generate_random_string(length=32, chars=allowed_chars):
|
|||
def generate_team_key():
|
||||
return config.ctf_name.lower() + "_" + generate_random_string(32, allowed_chars)
|
||||
|
||||
def generate_confirmation_key():
|
||||
return generate_random_string(48)
|
||||
|
||||
def get_ip():
|
||||
return request.headers.get(config.proxied_ip_header, request.remote_addr)
|
||||
|
||||
|
@ -26,6 +30,18 @@ def login_required(f):
|
|||
return f(*args, **kwargs)
|
||||
return decorated
|
||||
|
||||
def confirmed_email_required(f):
|
||||
@wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
if "team_id" not in session:
|
||||
flash("You need to be logged in to access that page.")
|
||||
return redirect(url_for('login'))
|
||||
if not g.team.email_confirmed:
|
||||
flash("You need to confirm your email in order to access that page.")
|
||||
return redirect(url_for('dashboard'))
|
||||
return f(*args, **kwargs)
|
||||
return decorated
|
||||
|
||||
def competition_running_required(f):
|
||||
@wraps(f)
|
||||
def decorated(*args, **kwargs):
|
||||
|
@ -78,3 +94,20 @@ def get_complex(key):
|
|||
|
||||
def set_complex(key, val, ex):
|
||||
g.redis.set(key, json.dumps(val), ex)
|
||||
|
||||
def send_email(to, subject, text):
|
||||
return requests.post("{}/messages".format(config.secret.mailgun_url), {"from": config.mail_from, "to": to, "subject": subject, "text": text}, auth=("api", config.secret.mailgun_key))
|
||||
|
||||
def send_confirmation_email(team_email, confirmation_key, team_key):
|
||||
send_email(team_email, "Welcome to {}!".format(config.ctf_name),
|
||||
"""Hello, and thanks for registering for {}! Before you can start solving problems,
|
||||
you must confirm your email by entering this code into the team dashboard:
|
||||
|
||||
{}
|
||||
|
||||
Once you've done that, your account will be enabled, and you will be able to access
|
||||
the challenges. If you have any trouble, feel free to contact an organizer!
|
||||
|
||||
If you didn't register an account, then you can disregard this email.
|
||||
|
||||
In case you lose it, your team key is: {}""".format(config.ctf_name, confirmation_key, team_key))
|
||||
|
|
Loading…
Reference in New Issue