We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Advice on E-mail Mechanism
It seems that when E-mail server and E-mail confirmation are enabled, CTFd will send a new E-mail to the E-mail address input by the new user every time he or she logged in without confirmation yet (At least my SMTP server does like that, I will be apologize if it is my own wrong configuration with my own server). I think it will be better that only one E-mail will be sent at the first time new user signs up, and provide a button allowing the unconfirmed user to receive a new confirmation E-mail if needed.

Anyway, Thanks for your excellent project!

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `CTFd/auth.py`
Content:
```
1 import logging
2 import os
3 import re
4 import time
5 import urllib
6 
7 from flask import current_app as app, render_template, request, redirect, url_for, session, Blueprint
8 from itsdangerous import TimedSerializer, BadTimeSignature, Signer, BadSignature
9 from passlib.hash import bcrypt_sha256
10 
11 from CTFd.models import db, Teams
12 from CTFd import utils
13 
14 auth = Blueprint('auth', __name__)
15 
16 
17 @auth.route('/confirm', methods=['POST', 'GET'])
18 @auth.route('/confirm/<data>', methods=['GET'])
19 def confirm_user(data=None):
20     if not utils.get_config('verify_emails'):
21         return redirect(url_for('challenges.challenges_view'))
22     if data and request.method == "GET":  # User is confirming email account
23         try:
24             s = Signer(app.config['SECRET_KEY'])
25             email = s.unsign(urllib.unquote_plus(data.decode('base64')))
26         except BadSignature:
27             return render_template('confirm.html', errors=['Your confirmation link seems wrong'])
28         except:
29             return render_template('confirm.html', errors=['Your link appears broken, please try again.'])
30         team = Teams.query.filter_by(email=email).first_or_404()
31         team.verified = True
32         db.session.commit()
33         logger = logging.getLogger('regs')
34         logger.warn("[{0}] {1} confirmed {2}".format(time.strftime("%m/%d/%Y %X"), team.name.encode('utf-8'), team.email.encode('utf-8')))
35         db.session.close()
36         if utils.authed():
37             return redirect(url_for('challenges.challenges_view'))
38         return redirect(url_for('auth.login'))
39     if not data and request.method == "GET":  # User has been directed to the confirm page because his account is not verified
40         if not utils.authed():
41             return redirect(url_for('auth.login'))
42         team = Teams.query.filter_by(id=session['id']).first_or_404()
43         if team.verified:
44             return redirect(url_for('views.profile'))
45         else:
46             utils.verify_email(team.email)
47         return render_template('confirm.html', team=team)
48 
49 
50 @auth.route('/reset_password', methods=['POST', 'GET'])
51 @auth.route('/reset_password/<data>', methods=['POST', 'GET'])
52 def reset_password(data=None):
53     if data is not None and request.method == "GET":
54         return render_template('reset_password.html', mode='set')
55     if data is not None and request.method == "POST":
56         try:
57             s = TimedSerializer(app.config['SECRET_KEY'])
58             name = s.loads(urllib.unquote_plus(data.decode('base64')), max_age=1800)
59         except BadTimeSignature:
60             return render_template('reset_password.html', errors=['Your link has expired'])
61         except:
62             return render_template('reset_password.html', errors=['Your link appears broken, please try again.'])
63         team = Teams.query.filter_by(name=name).first_or_404()
64         team.password = bcrypt_sha256.encrypt(request.form['password'].strip())
65         db.session.commit()
66         db.session.close()
67         return redirect(url_for('auth.login'))
68 
69     if request.method == 'POST':
70         email = request.form['email'].strip()
71         team = Teams.query.filter_by(email=email).first()
72         if not team:
73             return render_template('reset_password.html', errors=['If that account exists you will receive an email, please check your inbox'])
74         s = TimedSerializer(app.config['SECRET_KEY'])
75         token = s.dumps(team.name)
76         text = """
77 Did you initiate a password reset?
78 
79 {0}/{1}
80 
81 """.format(url_for('auth.reset_password', _external=True), urllib.quote_plus(token.encode('base64')))
82 
83         utils.sendmail(email, text)
84 
85         return render_template('reset_password.html', errors=['If that account exists you will receive an email, please check your inbox'])
86     return render_template('reset_password.html')
87 
88 
89 @auth.route('/register', methods=['POST', 'GET'])
90 def register():
91     if not utils.can_register():
92         return redirect(url_for('auth.login'))
93     if request.method == 'POST':
94         errors = []
95         name = request.form['name']
96         email = request.form['email']
97         password = request.form['password']
98 
99         name_len = len(name) == 0
100         names = Teams.query.add_columns('name', 'id').filter_by(name=name).first()
101         emails = Teams.query.add_columns('email', 'id').filter_by(email=email).first()
102         pass_short = len(password) == 0
103         pass_long = len(password) > 128
104         valid_email = re.match(r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)", request.form['email'])
105 
106         if not valid_email:
107             errors.append("That email doesn't look right")
108         if names:
109             errors.append('That team name is already taken')
110         if emails:
111             errors.append('That email has already been used')
112         if pass_short:
113             errors.append('Pick a longer password')
114         if pass_long:
115             errors.append('Pick a shorter password')
116         if name_len:
117             errors.append('Pick a longer team name')
118 
119         if len(errors) > 0:
120             return render_template('register.html', errors=errors, name=request.form['name'], email=request.form['email'], password=request.form['password'])
121         else:
122             with app.app_context():
123                 team = Teams(name, email.lower(), password)
124                 db.session.add(team)
125                 db.session.commit()
126                 db.session.flush()
127 
128                 session['username'] = team.name
129                 session['id'] = team.id
130                 session['admin'] = team.admin
131                 session['nonce'] = utils.sha512(os.urandom(10))
132 
133                 if utils.can_send_mail() and utils.get_config('verify_emails'):  # Confirming users is enabled and we can send email.
134                     db.session.close()
135                     logger = logging.getLogger('regs')
136                     logger.warn("[{0}] {1} registered (UNCONFIRMED) with {2}".format(time.strftime("%m/%d/%Y %X"),
137                                                                                      request.form['name'].encode('utf-8'),
138                                                                                      request.form['email'].encode('utf-8')))
139                     return redirect(url_for('auth.confirm_user'))
140                 else:  # Don't care about confirming users
141                     if utils.can_send_mail():  # We want to notify the user that they have registered.
142                         utils.sendmail(request.form['email'], "You've successfully registered for {}".format(utils.get_config('ctf_name')))
143 
144         db.session.close()
145 
146         logger = logging.getLogger('regs')
147         logger.warn("[{0}] {1} registered with {2}".format(time.strftime("%m/%d/%Y %X"), request.form['name'].encode('utf-8'), request.form['email'].encode('utf-8')))
148         return redirect(url_for('challenges.challenges_view'))
149     else:
150         return render_template('register.html')
151 
152 
153 @auth.route('/login', methods=['POST', 'GET'])
154 def login():
155     if request.method == 'POST':
156         errors = []
157         name = request.form['name']
158         team = Teams.query.filter_by(name=name).first()
159         if team:
160             if team and bcrypt_sha256.verify(request.form['password'], team.password):
161                 try:
162                     session.regenerate()  # NO SESSION FIXATION FOR YOU
163                 except:
164                     pass  # TODO: Some session objects don't implement regenerate :(
165                 session['username'] = team.name
166                 session['id'] = team.id
167                 session['admin'] = team.admin
168                 session['nonce'] = utils.sha512(os.urandom(10))
169                 db.session.close()
170 
171                 logger = logging.getLogger('logins')
172                 logger.warn("[{0}] {1} logged in".format(time.strftime("%m/%d/%Y %X"), session['username'].encode('utf-8')))
173 
174                 if request.args.get('next') and utils.is_safe_url(request.args.get('next')):
175                     return redirect(request.args.get('next'))
176                 return redirect(url_for('challenges.challenges_view'))
177             else:  # This user exists but the password is wrong
178                 errors.append("Your username or password is incorrect")
179                 db.session.close()
180                 return render_template('login.html', errors=errors)
181         else:  # This user just doesn't exist
182             errors.append("Your username or password is incorrect")
183             db.session.close()
184             return render_template('login.html', errors=errors)
185     else:
186         db.session.close()
187         return render_template('login.html')
188 
189 
190 @auth.route('/logout')
191 def logout():
192     if utils.authed():
193         session.clear()
194     return redirect(url_for('views.static_html'))
195
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/CTFd/auth.py b/CTFd/auth.py
--- a/CTFd/auth.py
+++ b/CTFd/auth.py
@@ -18,8 +18,11 @@
 @auth.route('/confirm/<data>', methods=['GET'])
 def confirm_user(data=None):
     if not utils.get_config('verify_emails'):
+        # If the CTF doesn't care about confirming email addresses then redierct to challenges
         return redirect(url_for('challenges.challenges_view'))
-    if data and request.method == "GET":  # User is confirming email account
+
+    # User is confirming email account
+    if data and request.method == "GET":
         try:
             s = Signer(app.config['SECRET_KEY'])
             email = s.unsign(urllib.unquote_plus(data.decode('base64')))
@@ -36,15 +39,28 @@
         if utils.authed():
             return redirect(url_for('challenges.challenges_view'))
         return redirect(url_for('auth.login'))
-    if not data and request.method == "GET":  # User has been directed to the confirm page because his account is not verified
-        if not utils.authed():
-            return redirect(url_for('auth.login'))
-        team = Teams.query.filter_by(id=session['id']).first_or_404()
-        if team.verified:
-            return redirect(url_for('views.profile'))
-        else:
-            utils.verify_email(team.email)
-        return render_template('confirm.html', team=team)
+
+    # User is trying to start or restart the confirmation flow
+    if not utils.authed():
+        return redirect(url_for('auth.login'))
+
+    team = Teams.query.filter_by(id=session['id']).first_or_404()
+
+    if data is None:
+        if request.method == "POST":
+            # User wants to resend their confirmation email
+            if team.verified:
+                return redirect(url_for('views.profile'))
+            else:
+                utils.verify_email(team.email)
+            return render_template('confirm.html', team=team, infos=['Your confirmation email has been resent!'])
+        elif request.method == "GET":
+            # User has been directed to the confirm page
+            team = Teams.query.filter_by(id=session['id']).first_or_404()
+            if team.verified:
+                # If user is already verified, redirect to their profile
+                return redirect(url_for('views.profile'))
+            return render_template('confirm.html', team=team)
 
 
 @auth.route('/reset_password', methods=['POST', 'GET'])
@@ -136,6 +152,9 @@
                     logger.warn("[{0}] {1} registered (UNCONFIRMED) with {2}".format(time.strftime("%m/%d/%Y %X"),
                                                                                      request.form['name'].encode('utf-8'),
                                                                                      request.form['email'].encode('utf-8')))
+
+                    utils.verify_email(team.email)
+
                     return redirect(url_for('auth.confirm_user'))
                 else:  # Don't care about confirming users
                     if utils.can_send_mail():  # We want to notify the user that they have registered.

{"golden_diff": "diff --git a/CTFd/auth.py b/CTFd/auth.py\n--- a/CTFd/auth.py\n+++ b/CTFd/auth.py\n@@ -18,8 +18,11 @@\n @auth.route('/confirm/<data>', methods=['GET'])\n def confirm_user(data=None):\n     if not utils.get_config('verify_emails'):\n+        # If the CTF doesn't care about confirming email addresses then redierct to challenges\n         return redirect(url_for('challenges.challenges_view'))\n-    if data and request.method == \"GET\":  # User is confirming email account\n+\n+    # User is confirming email account\n+    if data and request.method == \"GET\":\n         try:\n             s = Signer(app.config['SECRET_KEY'])\n             email = s.unsign(urllib.unquote_plus(data.decode('base64')))\n@@ -36,15 +39,28 @@\n         if utils.authed():\n             return redirect(url_for('challenges.challenges_view'))\n         return redirect(url_for('auth.login'))\n-    if not data and request.method == \"GET\":  # User has been directed to the confirm page because his account is not verified\n-        if not utils.authed():\n-            return redirect(url_for('auth.login'))\n-        team = Teams.query.filter_by(id=session['id']).first_or_404()\n-        if team.verified:\n-            return redirect(url_for('views.profile'))\n-        else:\n-            utils.verify_email(team.email)\n-        return render_template('confirm.html', team=team)\n+\n+    # User is trying to start or restart the confirmation flow\n+    if not utils.authed():\n+        return redirect(url_for('auth.login'))\n+\n+    team = Teams.query.filter_by(id=session['id']).first_or_404()\n+\n+    if data is None:\n+        if request.method == \"POST\":\n+            # User wants to resend their confirmation email\n+            if team.verified:\n+                return redirect(url_for('views.profile'))\n+            else:\n+                utils.verify_email(team.email)\n+            return render_template('confirm.html', team=team, infos=['Your confirmation email has been resent!'])\n+        elif request.method == \"GET\":\n+            # User has been directed to the confirm page\n+            team = Teams.query.filter_by(id=session['id']).first_or_404()\n+            if team.verified:\n+                # If user is already verified, redirect to their profile\n+                return redirect(url_for('views.profile'))\n+            return render_template('confirm.html', team=team)\n \n \n @auth.route('/reset_password', methods=['POST', 'GET'])\n@@ -136,6 +152,9 @@\n                     logger.warn(\"[{0}] {1} registered (UNCONFIRMED) with {2}\".format(time.strftime(\"%m/%d/%Y %X\"),\n                                                                                      request.form['name'].encode('utf-8'),\n                                                                                      request.form['email'].encode('utf-8')))\n+\n+                    utils.verify_email(team.email)\n+\n                     return redirect(url_for('auth.confirm_user'))\n                 else:  # Don't care about confirming users\n                     if utils.can_send_mail():  # We want to notify the user that they have registered.\n", "issue": "Advice on E-mail Mechanism\nIt seems that when E-mail server and E-mail confirmation are enabled, CTFd will send a new E-mail to the E-mail address input by the new user every time he or she logged in without confirmation yet (At least my SMTP server does like that, I will be apologize if it is my own wrong configuration with my own server). I think it will be better that only one E-mail will be sent at the first time new user signs up, and provide a button allowing the unconfirmed user to receive a new confirmation E-mail if needed.\r\n\r\nAnyway, Thanks for your excellent project!\n", "before_files": [{"content": "import logging\nimport os\nimport re\nimport time\nimport urllib\n\nfrom flask import current_app as app, render_template, request, redirect, url_for, session, Blueprint\nfrom itsdangerous import TimedSerializer, BadTimeSignature, Signer, BadSignature\nfrom passlib.hash import bcrypt_sha256\n\nfrom CTFd.models import db, Teams\nfrom CTFd import utils\n\nauth = Blueprint('auth', __name__)\n\n\n@auth.route('/confirm', methods=['POST', 'GET'])\n@auth.route('/confirm/<data>', methods=['GET'])\ndef confirm_user(data=None):\n    if not utils.get_config('verify_emails'):\n        return redirect(url_for('challenges.challenges_view'))\n    if data and request.method == \"GET\":  # User is confirming email account\n        try:\n            s = Signer(app.config['SECRET_KEY'])\n            email = s.unsign(urllib.unquote_plus(data.decode('base64')))\n        except BadSignature:\n            return render_template('confirm.html', errors=['Your confirmation link seems wrong'])\n        except:\n            return render_template('confirm.html', errors=['Your link appears broken, please try again.'])\n        team = Teams.query.filter_by(email=email).first_or_404()\n        team.verified = True\n        db.session.commit()\n        logger = logging.getLogger('regs')\n        logger.warn(\"[{0}] {1} confirmed {2}\".format(time.strftime(\"%m/%d/%Y %X\"), team.name.encode('utf-8'), team.email.encode('utf-8')))\n        db.session.close()\n        if utils.authed():\n            return redirect(url_for('challenges.challenges_view'))\n        return redirect(url_for('auth.login'))\n    if not data and request.method == \"GET\":  # User has been directed to the confirm page because his account is not verified\n        if not utils.authed():\n            return redirect(url_for('auth.login'))\n        team = Teams.query.filter_by(id=session['id']).first_or_404()\n        if team.verified:\n            return redirect(url_for('views.profile'))\n        else:\n            utils.verify_email(team.email)\n        return render_template('confirm.html', team=team)\n\n\n@auth.route('/reset_password', methods=['POST', 'GET'])\n@auth.route('/reset_password/<data>', methods=['POST', 'GET'])\ndef reset_password(data=None):\n    if data is not None and request.method == \"GET\":\n        return render_template('reset_password.html', mode='set')\n    if data is not None and request.method == \"POST\":\n        try:\n            s = TimedSerializer(app.config['SECRET_KEY'])\n            name = s.loads(urllib.unquote_plus(data.decode('base64')), max_age=1800)\n        except BadTimeSignature:\n            return render_template('reset_password.html', errors=['Your link has expired'])\n        except:\n            return render_template('reset_password.html', errors=['Your link appears broken, please try again.'])\n        team = Teams.query.filter_by(name=name).first_or_404()\n        team.password = bcrypt_sha256.encrypt(request.form['password'].strip())\n        db.session.commit()\n        db.session.close()\n        return redirect(url_for('auth.login'))\n\n    if request.method == 'POST':\n        email = request.form['email'].strip()\n        team = Teams.query.filter_by(email=email).first()\n        if not team:\n            return render_template('reset_password.html', errors=['If that account exists you will receive an email, please check your inbox'])\n        s = TimedSerializer(app.config['SECRET_KEY'])\n        token = s.dumps(team.name)\n        text = \"\"\"\nDid you initiate a password reset?\n\n{0}/{1}\n\n\"\"\".format(url_for('auth.reset_password', _external=True), urllib.quote_plus(token.encode('base64')))\n\n        utils.sendmail(email, text)\n\n        return render_template('reset_password.html', errors=['If that account exists you will receive an email, please check your inbox'])\n    return render_template('reset_password.html')\n\n\n@auth.route('/register', methods=['POST', 'GET'])\ndef register():\n    if not utils.can_register():\n        return redirect(url_for('auth.login'))\n    if request.method == 'POST':\n        errors = []\n        name = request.form['name']\n        email = request.form['email']\n        password = request.form['password']\n\n        name_len = len(name) == 0\n        names = Teams.query.add_columns('name', 'id').filter_by(name=name).first()\n        emails = Teams.query.add_columns('email', 'id').filter_by(email=email).first()\n        pass_short = len(password) == 0\n        pass_long = len(password) > 128\n        valid_email = re.match(r\"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$)\", request.form['email'])\n\n        if not valid_email:\n            errors.append(\"That email doesn't look right\")\n        if names:\n            errors.append('That team name is already taken')\n        if emails:\n            errors.append('That email has already been used')\n        if pass_short:\n            errors.append('Pick a longer password')\n        if pass_long:\n            errors.append('Pick a shorter password')\n        if name_len:\n            errors.append('Pick a longer team name')\n\n        if len(errors) > 0:\n            return render_template('register.html', errors=errors, name=request.form['name'], email=request.form['email'], password=request.form['password'])\n        else:\n            with app.app_context():\n                team = Teams(name, email.lower(), password)\n                db.session.add(team)\n                db.session.commit()\n                db.session.flush()\n\n                session['username'] = team.name\n                session['id'] = team.id\n                session['admin'] = team.admin\n                session['nonce'] = utils.sha512(os.urandom(10))\n\n                if utils.can_send_mail() and utils.get_config('verify_emails'):  # Confirming users is enabled and we can send email.\n                    db.session.close()\n                    logger = logging.getLogger('regs')\n                    logger.warn(\"[{0}] {1} registered (UNCONFIRMED) with {2}\".format(time.strftime(\"%m/%d/%Y %X\"),\n                                                                                     request.form['name'].encode('utf-8'),\n                                                                                     request.form['email'].encode('utf-8')))\n                    return redirect(url_for('auth.confirm_user'))\n                else:  # Don't care about confirming users\n                    if utils.can_send_mail():  # We want to notify the user that they have registered.\n                        utils.sendmail(request.form['email'], \"You've successfully registered for {}\".format(utils.get_config('ctf_name')))\n\n        db.session.close()\n\n        logger = logging.getLogger('regs')\n        logger.warn(\"[{0}] {1} registered with {2}\".format(time.strftime(\"%m/%d/%Y %X\"), request.form['name'].encode('utf-8'), request.form['email'].encode('utf-8')))\n        return redirect(url_for('challenges.challenges_view'))\n    else:\n        return render_template('register.html')\n\n\n@auth.route('/login', methods=['POST', 'GET'])\ndef login():\n    if request.method == 'POST':\n        errors = []\n        name = request.form['name']\n        team = Teams.query.filter_by(name=name).first()\n        if team:\n            if team and bcrypt_sha256.verify(request.form['password'], team.password):\n                try:\n                    session.regenerate()  # NO SESSION FIXATION FOR YOU\n                except:\n                    pass  # TODO: Some session objects don't implement regenerate :(\n                session['username'] = team.name\n                session['id'] = team.id\n                session['admin'] = team.admin\n                session['nonce'] = utils.sha512(os.urandom(10))\n                db.session.close()\n\n                logger = logging.getLogger('logins')\n                logger.warn(\"[{0}] {1} logged in\".format(time.strftime(\"%m/%d/%Y %X\"), session['username'].encode('utf-8')))\n\n                if request.args.get('next') and utils.is_safe_url(request.args.get('next')):\n                    return redirect(request.args.get('next'))\n                return redirect(url_for('challenges.challenges_view'))\n            else:  # This user exists but the password is wrong\n                errors.append(\"Your username or password is incorrect\")\n                db.session.close()\n                return render_template('login.html', errors=errors)\n        else:  # This user just doesn't exist\n            errors.append(\"Your username or password is incorrect\")\n            db.session.close()\n            return render_template('login.html', errors=errors)\n    else:\n        db.session.close()\n        return render_template('login.html')\n\n\n@auth.route('/logout')\ndef logout():\n    if utils.authed():\n        session.clear()\n    return redirect(url_for('views.static_html'))\n", "path": "CTFd/auth.py"}], "after_files": [{"content": "import logging\nimport os\nimport re\nimport time\nimport urllib\n\nfrom flask import current_app as app, render_template, request, redirect, url_for, session, Blueprint\nfrom itsdangerous import TimedSerializer, BadTimeSignature, Signer, BadSignature\nfrom passlib.hash import bcrypt_sha256\n\nfrom CTFd.models import db, Teams\nfrom CTFd import utils\n\nauth = Blueprint('auth', __name__)\n\n\n@auth.route('/confirm', methods=['POST', 'GET'])\n@auth.route('/confirm/<data>', methods=['GET'])\ndef confirm_user(data=None):\n    if not utils.get_config('verify_emails'):\n        # If the CTF doesn't care about confirming email addresses then redierct to challenges\n        return redirect(url_for('challenges.challenges_view'))\n\n    # User is confirming email account\n    if data and request.method == \"GET\":\n        try:\n            s = Signer(app.config['SECRET_KEY'])\n            email = s.unsign(urllib.unquote_plus(data.decode('base64')))\n        except BadSignature:\n            return render_template('confirm.html', errors=['Your confirmation link seems wrong'])\n        except:\n            return render_template('confirm.html', errors=['Your link appears broken, please try again.'])\n        team = Teams.query.filter_by(email=email).first_or_404()\n        team.verified = True\n        db.session.commit()\n        logger = logging.getLogger('regs')\n        logger.warn(\"[{0}] {1} confirmed {2}\".format(time.strftime(\"%m/%d/%Y %X\"), team.name.encode('utf-8'), team.email.encode('utf-8')))\n        db.session.close()\n        if utils.authed():\n            return redirect(url_for('challenges.challenges_view'))\n        return redirect(url_for('auth.login'))\n\n    # User is trying to start or restart the confirmation flow\n    if not utils.authed():\n        return redirect(url_for('auth.login'))\n\n    team = Teams.query.filter_by(id=session['id']).first_or_404()\n\n    if data is None:\n        if request.method == \"POST\":\n            # User wants to resend their confirmation email\n            if team.verified:\n                return redirect(url_for('views.profile'))\n            else:\n                utils.verify_email(team.email)\n            return render_template('confirm.html', team=team, infos=['Your confirmation email has been resent!'])\n        elif request.method == \"GET\":\n            # User has been directed to the confirm page\n            team = Teams.query.filter_by(id=session['id']).first_or_404()\n            if team.verified:\n                # If user is already verified, redirect to their profile\n                return redirect(url_for('views.profile'))\n            return render_template('confirm.html', team=team)\n\n\n@auth.route('/reset_password', methods=['POST', 'GET'])\n@auth.route('/reset_password/<data>', methods=['POST', 'GET'])\ndef reset_password(data=None):\n    if data is not None and request.method == \"GET\":\n        return render_template('reset_password.html', mode='set')\n    if data is not None and request.method == \"POST\":\n        try:\n            s = TimedSerializer(app.config['SECRET_KEY'])\n            name = s.loads(urllib.unquote_plus(data.decode('base64')), max_age=1800)\n        except BadTimeSignature:\n            return render_template('reset_password.html', errors=['Your link has expired'])\n        except:\n            return render_template('reset_password.html', errors=['Your link appears broken, please try again.'])\n        team = Teams.query.filter_by(name=name).first_or_404()\n        team.password = bcrypt_sha256.encrypt(request.form['password'].strip())\n        db.session.commit()\n        db.session.close()\n        return redirect(url_for('auth.login'))\n\n    if request.method == 'POST':\n        email = request.form['email'].strip()\n        team = Teams.query.filter_by(email=email).first()\n        if not team:\n            return render_template('reset_password.html', errors=['If that account exists you will receive an email, please check your inbox'])\n        s = TimedSerializer(app.config['SECRET_KEY'])\n        token = s.dumps(team.name)\n        text = \"\"\"\nDid you initiate a password reset?\n\n{0}/{1}\n\n\"\"\".format(url_for('auth.reset_password', _external=True), urllib.quote_plus(token.encode('base64')))\n\n        utils.sendmail(email, text)\n\n        return render_template('reset_password.html', errors=['If that account exists you will receive an email, please check your inbox'])\n    return render_template('reset_password.html')\n\n\n@auth.route('/register', methods=['POST', 'GET'])\ndef register():\n    if not utils.can_register():\n        return redirect(url_for('auth.login'))\n    if request.method == 'POST':\n        errors = []\n        name = request.form['name']\n        email = request.form['email']\n        password = request.form['password']\n\n        name_len = len(name) == 0\n        names = Teams.query.add_columns('name', 'id').filter_by(name=name).first()\n        emails = Teams.query.add_columns('email', 'id').filter_by(email=email).first()\n        pass_short = len(password) == 0\n        pass_long = len(password) > 128\n        valid_email = re.match(r\"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\\.[a-zA-Z0-9-.]+$)\", request.form['email'])\n\n        if not valid_email:\n            errors.append(\"That email doesn't look right\")\n        if names:\n            errors.append('That team name is already taken')\n        if emails:\n            errors.append('That email has already been used')\n        if pass_short:\n            errors.append('Pick a longer password')\n        if pass_long:\n            errors.append('Pick a shorter password')\n        if name_len:\n            errors.append('Pick a longer team name')\n\n        if len(errors) > 0:\n            return render_template('register.html', errors=errors, name=request.form['name'], email=request.form['email'], password=request.form['password'])\n        else:\n            with app.app_context():\n                team = Teams(name, email.lower(), password)\n                db.session.add(team)\n                db.session.commit()\n                db.session.flush()\n\n                session['username'] = team.name\n                session['id'] = team.id\n                session['admin'] = team.admin\n                session['nonce'] = utils.sha512(os.urandom(10))\n\n                if utils.can_send_mail() and utils.get_config('verify_emails'):  # Confirming users is enabled and we can send email.\n                    db.session.close()\n                    logger = logging.getLogger('regs')\n                    logger.warn(\"[{0}] {1} registered (UNCONFIRMED) with {2}\".format(time.strftime(\"%m/%d/%Y %X\"),\n                                                                                     request.form['name'].encode('utf-8'),\n                                                                                     request.form['email'].encode('utf-8')))\n\n                    utils.verify_email(team.email)\n\n                    return redirect(url_for('auth.confirm_user'))\n                else:  # Don't care about confirming users\n                    if utils.can_send_mail():  # We want to notify the user that they have registered.\n                        utils.sendmail(request.form['email'], \"You've successfully registered for {}\".format(utils.get_config('ctf_name')))\n\n        db.session.close()\n\n        logger = logging.getLogger('regs')\n        logger.warn(\"[{0}] {1} registered with {2}\".format(time.strftime(\"%m/%d/%Y %X\"), request.form['name'].encode('utf-8'), request.form['email'].encode('utf-8')))\n        return redirect(url_for('challenges.challenges_view'))\n    else:\n        return render_template('register.html')\n\n\n@auth.route('/login', methods=['POST', 'GET'])\ndef login():\n    if request.method == 'POST':\n        errors = []\n        name = request.form['name']\n        team = Teams.query.filter_by(name=name).first()\n        if team:\n            if team and bcrypt_sha256.verify(request.form['password'], team.password):\n                try:\n                    session.regenerate()  # NO SESSION FIXATION FOR YOU\n                except:\n                    pass  # TODO: Some session objects don't implement regenerate :(\n                session['username'] = team.name\n                session['id'] = team.id\n                session['admin'] = team.admin\n                session['nonce'] = utils.sha512(os.urandom(10))\n                db.session.close()\n\n                logger = logging.getLogger('logins')\n                logger.warn(\"[{0}] {1} logged in\".format(time.strftime(\"%m/%d/%Y %X\"), session['username'].encode('utf-8')))\n\n                if request.args.get('next') and utils.is_safe_url(request.args.get('next')):\n                    return redirect(request.args.get('next'))\n                return redirect(url_for('challenges.challenges_view'))\n            else:  # This user exists but the password is wrong\n                errors.append(\"Your username or password is incorrect\")\n                db.session.close()\n                return render_template('login.html', errors=errors)\n        else:  # This user just doesn't exist\n            errors.append(\"Your username or password is incorrect\")\n            db.session.close()\n            return render_template('login.html', errors=errors)\n    else:\n        db.session.close()\n        return render_template('login.html')\n\n\n@auth.route('/logout')\ndef logout():\n    if utils.authed():\n        session.clear()\n    return redirect(url_for('views.static_html'))\n", "path": "CTFd/auth.py"}]}