From fd043890746fd13f8c736470f95662c8509c29c0 Mon Sep 17 00:00:00 2001
From: Julian Rother <julianr@fsmpi.rwth-aachen.de>
Date: Sat, 15 May 2021 21:46:01 +0200
Subject: [PATCH] Limited invite validity period, extended token entropy, other
 small fixes

---
 uffd/default_config.cfg               | 2 ++
 uffd/invite/models.py                 | 2 +-
 uffd/invite/templates/invite/new.html | 8 ++++----
 uffd/invite/views.py                  | 5 ++++-
 uffd/signup/models.py                 | 2 +-
 5 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/uffd/default_config.cfg b/uffd/default_config.cfg
index debf69eb..55962602 100644
--- a/uffd/default_config.cfg
+++ b/uffd/default_config.cfg
@@ -69,6 +69,8 @@ ENABLE_PASSWORDRESET=True
 # Do not enable this on a public service! There is no spam protection implemented at the moment.
 SELF_SIGNUP=False
 
+INVITE_MAX_VALID_DAYS=21
+
 LOGINNAME_BLACKLIST=['^admin$', '^root$']
 
 #MFA_ICON_URL = 'https://example.com/logo.png'
diff --git a/uffd/invite/models.py b/uffd/invite/models.py
index eb441fb9..47826cd0 100644
--- a/uffd/invite/models.py
+++ b/uffd/invite/models.py
@@ -19,7 +19,7 @@ invite_roles = db.Table('invite_roles',
 class Invite(db.Model):
 	__tablename__ = 'invite'
 	id = Column(Integer(), primary_key=True, autoincrement=True)
-	token = Column(String(128), unique=True, nullable=False, default=lambda: secrets.token_urlsafe(32))
+	token = Column(String(128), unique=True, nullable=False, default=lambda: secrets.token_urlsafe(48))
 	created = Column(DateTime, default=datetime.datetime.now, nullable=False)
 	creator_dn = Column(String(128), nullable=True)
 	creator = DBRelationship('creator_dn', User)
diff --git a/uffd/invite/templates/invite/new.html b/uffd/invite/templates/invite/new.html
index d1f913ac..a27d50d6 100644
--- a/uffd/invite/templates/invite/new.html
+++ b/uffd/invite/templates/invite/new.html
@@ -10,8 +10,9 @@
 		</select>
 	</div>
 	<div class="form-group">
-		<label for="valid-until">Expires After</label>
+		<label for="valid-until">Valid Until</label>
 		<input class="form-control" type="datetime-local" id="valid-until" name="valid-until" value="{{ (datetime.now() + timedelta(hours=36)).replace(hour=23, minute=59, second=59, microsecond=0).isoformat(timespec='minutes') }}">
+		<small class="text-muted">Must be within the next {{ config['INVITE_MAX_VALID_DAYS'] }} days</small>
 	</div>
 	{% if allow_signup %}
 	<div class="form-group">
@@ -24,6 +25,7 @@
 	{% else %}
 	<input type="hidden" name="allow-signup" value="0">
 	{% endif %}
+	{% if roles %}
 	<div class="form-group">
 		<label for="valid-until">Granted Roles</label>
 		<table class="table table-sm">
@@ -46,12 +48,10 @@
 					<td>{{ role.description }}</td>
 				</tr>
 				{% endfor %}
-				{% if not roles %}
-				<tr><td colspan="3" class="bg-light text-muted text-center">There are no (non-base) roles yet</td></tr>
-				{% endif %}
 			</tbody>
 		</table>
 	</div>
+	{% endif %}
 	<button type="submit" class="btn btn-primary"><i class="fa fa-save" aria-hidden="true"></i> Create Link</button>
 	<a href="{{ url_for("invite.index") }}" class="btn btn-secondary">Cancel</a>
 </form>
diff --git a/uffd/invite/views.py b/uffd/invite/views.py
index d7a9eedc..bfe9af36 100644
--- a/uffd/invite/views.py
+++ b/uffd/invite/views.py
@@ -76,10 +76,13 @@ def new_submit():
 	invite = Invite(creator=user,
 	                single_use=(request.values['single-use'] == '1'),
 	                valid_until=datetime.datetime.fromisoformat(request.values['valid-until']),
-	                allow_signup=(request.values['allow-signup'] == '1'))
+	                allow_signup=(request.values.get('allow-signup', '0') == '1'))
 	for key, value in request.values.items():
 		if key.startswith('role-') and value == '1':
 			invite.roles.append(Role.query.get(key[5:]))
+	if invite.valid_until > datetime.datetime.now() + datetime.timedelta(days=current_app.config['INVITE_MAX_VALID_DAYS']):
+		flash('The "Expires After" date is too far in the future')
+		return redirect(url_for('invite.new'))
 	if not invite.permitted:
 		flash('You are not allowed to create invite links with these permissions')
 		return redirect(url_for('invite.new'))
diff --git a/uffd/signup/models.py b/uffd/signup/models.py
index a2f4b721..2fabc8e5 100644
--- a/uffd/signup/models.py
+++ b/uffd/signup/models.py
@@ -28,7 +28,7 @@ class Signup(db.Model):
 	As long as they are not completed, signup requests have no effect each other
 	or different parts of the application.'''
 	__tablename__ = 'signup'
-	token = Column(String(128), primary_key=True, default=lambda: secrets.token_urlsafe(32))
+	token = Column(String(128), primary_key=True, default=lambda: secrets.token_urlsafe(48))
 	created = Column(DateTime, default=datetime.datetime.now, nullable=False)
 	loginname = Column(Text)
 	displayname = Column(Text)
-- 
GitLab