2
0

login/logout: check client mac from form as csrf protection, check accept in login

This commit is contained in:
Stefan Bühler 2022-04-07 15:11:24 +02:00
parent 237640f0d7
commit 2e6b368670
3 changed files with 25 additions and 5 deletions

View File

@ -5,9 +5,11 @@ You already accepted out conditions and are currently granted access to the inte
Your current session will last for {{ state.allowed_remaining }} seconds.
<form method="POST" action="/login">
<input type="hidden" name="accept" value="1">
<input type="hidden" name="mac" value="{{ state.mac }}">
<button type="submit" class="btn btn-primary mb-3">Extend session</button>
</form>
<form method="POST" action="/logout">
<input type="hidden" name="mac" value="{{ state.mac }}">
<button type="submit" class="btn btn-danger mb-3">Terminate session</button>
</form>
<br>

View File

@ -3,6 +3,7 @@
To get access to the internet please accept our usage guidelines by clicking this button:
<form method="POST" action="/login">
<input type="hidden" name="accept" value="1">
<input type="hidden" name="mac" value="{{ state.mac }}">
<button type="submit" class="btn btn-primary mb-3">Accept</button>
</form>
{% endblock %}

View File

@ -10,12 +10,12 @@ import capport.database
import capport.utils.cli
import capport.utils.ipneigh
import quart
import trio
from capport import cptypes
from .app import app
from .lang import render_i18n_template
_logger = logging.getLogger(__name__)
@ -97,27 +97,44 @@ async def user_lookup() -> cptypes.MacPublicState:
@app.route('/', methods=['GET'])
async def index():
async def index(missing_accept: bool=False):
state = await user_lookup()
return await render_i18n_template('index_active.html', state=state, missing_accept=missing_accept)
if not state.mac:
return await render_i18n_template('index_unknown.html', state=state)
return await render_i18n_template('index_unknown.html', state=state, missing_accept=missing_accept)
elif state.allowed:
return await render_i18n_template('index_active.html', state=state)
return await render_i18n_template('index_active.html', state=state, missing_accept=missing_accept)
else:
return await render_i18n_template('index_inactive.html', state=state)
return await render_i18n_template('index_inactive.html', state=state, missing_accept=missing_accept)
@app.route('/login', methods=['POST'])
async def login():
with trio.fail_after(5.0):
form = await quart.request.form
if form.get('accept') != '1':
return await index(missing_accept=True)
req_mac = form.get('mac')
if not req_mac:
quart.abort(400, description='Missing MAC in request form data')
address = get_client_ip()
mac = await get_client_mac(address)
if str(mac) != req_mac:
quart.abort(403, description="Passed MAC in request form doesn't match client address")
await user_login(address, mac)
return quart.redirect('/', code=303)
@app.route('/logout', methods=['POST'])
async def logout():
with trio.fail_after(5.0):
form = await quart.request.form
req_mac = form.get('mac')
if not req_mac:
quart.abort(400, description='Missing MAC in request form data')
mac = await get_client_mac()
if str(mac) != req_mac:
quart.abort(403, description="Passed MAC in request form doesn't match client address")
await user_logout(mac)
return quart.redirect('/', code=303)