diff --git a/tests/test_invite.py b/tests/test_invite.py index 295103208ecd1f1436e4066e7fadd5fe55c2f226..93dea192ec59f0fe15236cda36106f0e6ebe5bd9 100644 --- a/tests/test_invite.py +++ b/tests/test_invite.py @@ -12,21 +12,21 @@ from utils import dump, UffdTestCase, db_flush class TestInviteModel(UffdTestCase): def test_expire(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), creator=self.get_admin()) self.assertFalse(invite.expired) self.assertTrue(invite.active) - invite.valid_until = datetime.datetime.now() - datetime.timedelta(seconds=60) + invite.valid_until = datetime.datetime.utcnow() - datetime.timedelta(seconds=60) self.assertTrue(invite.expired) self.assertFalse(invite.active) def test_void(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), single_use=False, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), single_use=False, creator=self.get_admin()) self.assertFalse(invite.voided) self.assertTrue(invite.active) invite.used = True self.assertFalse(invite.voided) self.assertTrue(invite.active) - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), single_use=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), single_use=True, creator=self.get_admin()) self.assertFalse(invite.voided) self.assertTrue(invite.active) invite.used = True @@ -35,7 +35,7 @@ class TestInviteModel(UffdTestCase): def test_permitted(self): role = Role(name='testrole') - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, roles=[role]) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, roles=[role]) self.assertFalse(invite.permitted) self.assertFalse(invite.active) invite.creator = self.get_admin() @@ -57,26 +57,26 @@ class TestInviteModel(UffdTestCase): self.assertFalse(invite.active) def test_disable(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), creator=self.get_admin()) self.assertTrue(invite.active) invite.disable() self.assertFalse(invite.active) def test_reset_disabled(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), creator=self.get_admin()) invite.disable() self.assertFalse(invite.active) invite.reset() self.assertTrue(invite.active) def test_reset_expired(self): - invite = Invite(valid_until=datetime.datetime.now() - datetime.timedelta(seconds=60), creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() - datetime.timedelta(seconds=60), creator=self.get_admin()) self.assertFalse(invite.active) invite.reset() self.assertFalse(invite.active) def test_reset_single_use(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), single_use=False, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), single_use=False, creator=self.get_admin()) invite.used = True invite.disable() self.assertFalse(invite.active) @@ -84,7 +84,7 @@ class TestInviteModel(UffdTestCase): self.assertTrue(invite.active) def test_short_token(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), creator=self.get_admin()) db.session.add(invite) db.session.commit() self.assertTrue(len(invite.short_token) <= len(invite.token)/3) @@ -102,7 +102,7 @@ class TestInviteGrantModel(UffdTestCase): db.session.add(role1) role2 = Role(name='testrole2') db.session.add(role2) - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), roles=[role1, role2], creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), roles=[role1, role2], creator=self.get_admin()) self.assertIn(role0, user.roles) self.assertNotIn(role1, user.roles) self.assertNotIn(role2, user.roles) @@ -132,7 +132,7 @@ class TestInviteGrantModel(UffdTestCase): group = self.get_admin_group() role = Role(name='testrole1', groups={group: RoleGroup(group=group)}) db.session.add(role) - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), roles=[role], single_use=True, used=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), roles=[role], single_use=True, used=True, creator=self.get_admin()) self.assertFalse(invite.active) grant = InviteGrant(invite=invite, user=user) success, msg = grant.apply() @@ -143,7 +143,7 @@ class TestInviteGrantModel(UffdTestCase): def test_no_roles(self): user = self.get_user() - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), creator=self.get_admin()) self.assertTrue(invite.active) grant = InviteGrant(invite=invite, user=user) success, msg = grant.apply() @@ -155,7 +155,7 @@ class TestInviteGrantModel(UffdTestCase): role = Role(name='testrole1') db.session.add(role) user.roles.append(role) - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), roles=[role], creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), roles=[role], creator=self.get_admin()) self.assertTrue(invite.active) grant = InviteGrant(invite=invite, user=user) success, msg = grant.apply() @@ -180,7 +180,7 @@ class TestInviteSignupModel(UffdTestCase): db.session.add(role1) role2 = Role(name='testrole2') db.session.add(role2) - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), roles=[role1, role2], allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), roles=[role1, role2], allow_signup=True, creator=self.get_admin()) signup = InviteSignup(invite=invite, loginname='newuser', displayname='New User', mail='test@example.com', password='notsecret') self.assertFalse(invite.used) valid, msg = signup.validate() @@ -208,7 +208,7 @@ class TestInviteSignupModel(UffdTestCase): base_role = Role.query.filter_by(name='base').one() base_group1 = self.get_access_group() base_group2 = self.get_users_group() - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) signup = InviteSignup(invite=invite, loginname='newuser', displayname='New User', mail='test@example.com', password='notsecret') self.assertFalse(invite.used) valid, msg = signup.validate() @@ -231,7 +231,7 @@ class TestInviteSignupModel(UffdTestCase): self.assertEqual(len(User.query.filter_by(loginname='newuser').all()), 1) def test_inactive(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, single_use=True, used=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, single_use=True, used=True, creator=self.get_admin()) self.assertFalse(invite.active) signup = InviteSignup(invite=invite, loginname='newuser', displayname='New User', mail='test@example.com', password='notsecret') valid, msg = signup.validate() @@ -242,7 +242,7 @@ class TestInviteSignupModel(UffdTestCase): self.assertIsInstance(msg, str) def test_invalid(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) self.assertTrue(invite.active) signup = InviteSignup(invite=invite, loginname='', displayname='New User', mail='test@example.com', password='notsecret') valid, msg = signup.validate() @@ -250,7 +250,7 @@ class TestInviteSignupModel(UffdTestCase): self.assertIsInstance(msg, str) def test_invalid2(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) self.assertTrue(invite.active) signup = InviteSignup(invite=invite, loginname='newuser', displayname='New User', mail='test@example.com', password='notsecret') user, msg = signup.finish('wrongpassword') @@ -258,7 +258,7 @@ class TestInviteSignupModel(UffdTestCase): self.assertIsInstance(msg, str) def test_no_signup(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=False, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=False, creator=self.get_admin()) self.assertTrue(invite.active) signup = InviteSignup(invite=invite, loginname='newuser', displayname='New User', mail='test@example.com', password='notsecret') valid, msg = signup.validate() @@ -274,8 +274,8 @@ class TestInviteAdminViews(UffdTestCase): self.app.last_mail = None def test_index(self): - valid_until = datetime.datetime.now() + datetime.timedelta(seconds=60) - valid_until_expired = datetime.datetime.now() - datetime.timedelta(seconds=60) + valid_until = datetime.datetime.utcnow() + datetime.timedelta(seconds=60) + valid_until_expired = datetime.datetime.utcnow() - datetime.timedelta(seconds=60) user1 = self.get_user() user2 = self.get_admin() role1 = Role(name='testrole1') @@ -320,7 +320,7 @@ class TestInviteAdminViews(UffdTestCase): def test_index_signupperm(self): current_app.config['ACL_SIGNUP_GROUP'] = 'uffd_access' - valid_until = datetime.datetime.now() + datetime.timedelta(seconds=60) + valid_until = datetime.datetime.utcnow() + datetime.timedelta(seconds=60) invite1 = Invite(valid_until=valid_until, allow_signup=True, creator=self.get_admin()) db.session.add(invite1) invite2 = Invite(valid_until=valid_until, allow_signup=True, creator=self.get_user()) @@ -343,7 +343,7 @@ class TestInviteAdminViews(UffdTestCase): db.session.add(role1) role2 = Role(name='testrole2', moderator_group=self.get_access_group()) db.session.add(role2) - valid_until = datetime.datetime.now() + datetime.timedelta(seconds=60) + valid_until = datetime.datetime.utcnow() + datetime.timedelta(seconds=60) db.session.add(Invite(valid_until=valid_until, roles=[role1])) db.session.add(Invite(valid_until=valid_until, roles=[role2])) db.session.commit() @@ -362,10 +362,10 @@ class TestInviteAdminViews(UffdTestCase): r = self.client.get(path=url_for('invite.new'), follow_redirects=True) dump('invite_new', r) self.assertEqual(r.status_code, 200) - valid_until = (datetime.datetime.now() + datetime.timedelta(seconds=60)).isoformat(timespec='minutes') + valid_until_input = (datetime.datetime.now() + datetime.timedelta(seconds=60)).isoformat(timespec='minutes') self.assertListEqual(Invite.query.all(), []) r = self.client.post(path=url_for('invite.new_submit'), - data={'single-use': '1', 'valid-until': valid_until, + data={'single-use': '1', 'valid-until': valid_until_input, 'allow-signup': '1', 'role-%d'%role_id: '1'}, follow_redirects=True) dump('invite_new_submit', r) invite = Invite.query.one() @@ -382,9 +382,9 @@ class TestInviteAdminViews(UffdTestCase): db.session.add(role) db.session.commit() role_id = role.id - valid_until = (datetime.datetime.now() + datetime.timedelta(seconds=60)).isoformat(timespec='minutes') + valid_until_input = (datetime.datetime.now() + datetime.timedelta(seconds=60)).isoformat(timespec='minutes') r = self.client.post(path=url_for('invite.new_submit'), - data={'single-use': '1', 'valid-until': valid_until, + data={'single-use': '1', 'valid-until': valid_until_input, 'allow-signup': '1', 'role-%d'%role_id: '1'}, follow_redirects=True) dump('invite_new_noperm', r) self.assertIsNone(Invite.query.first()) @@ -392,16 +392,16 @@ class TestInviteAdminViews(UffdTestCase): def test_new_empty(self): current_app.config['ACL_SIGNUP_GROUP'] = 'uffd_access' self.login_as('user') - valid_until = (datetime.datetime.now() + datetime.timedelta(seconds=60)).isoformat(timespec='minutes') + valid_until_input = (datetime.datetime.now() + datetime.timedelta(seconds=60)).isoformat(timespec='minutes') r = self.client.post(path=url_for('invite.new_submit'), - data={'single-use': '1', 'valid-until': valid_until, + data={'single-use': '1', 'valid-until': valid_until_input, 'allow-signup': '0'}, follow_redirects=True) dump('invite_new_empty', r) self.assertIsNone(Invite.query.first()) def test_disable(self): self.login_as('admin') - valid_until = datetime.datetime.now() + datetime.timedelta(seconds=60) + valid_until = datetime.datetime.utcnow() + datetime.timedelta(seconds=60) invite = Invite(valid_until=valid_until, creator=self.get_admin()) db.session.add(invite) db.session.commit() @@ -414,7 +414,7 @@ class TestInviteAdminViews(UffdTestCase): def test_disable_own(self): current_app.config['ACL_SIGNUP_GROUP'] = 'uffd_access' self.login_as('user') - valid_until = datetime.datetime.now() + datetime.timedelta(seconds=60) + valid_until = datetime.datetime.utcnow() + datetime.timedelta(seconds=60) invite = Invite(valid_until=valid_until, creator=self.get_user()) db.session.add(invite) db.session.commit() @@ -426,7 +426,7 @@ class TestInviteAdminViews(UffdTestCase): def test_disable_rolemod(self): self.login_as('user') - valid_until = datetime.datetime.now() + datetime.timedelta(seconds=60) + valid_until = datetime.datetime.utcnow() + datetime.timedelta(seconds=60) role = Role(name='testrole', moderator_group=self.get_access_group()) db.session.add(role) invite = Invite(valid_until=valid_until, creator=self.get_admin(), roles=[role]) @@ -439,7 +439,7 @@ class TestInviteAdminViews(UffdTestCase): def test_disable_noperm(self): self.login_as('user') - valid_until = datetime.datetime.now() + datetime.timedelta(seconds=60) + valid_until = datetime.datetime.utcnow() + datetime.timedelta(seconds=60) db.session.add(Role(name='testrole1', moderator_group=self.get_access_group())) role = Role(name='testrole2', moderator_group=self.get_admin_group()) db.session.add(role) @@ -453,7 +453,7 @@ class TestInviteAdminViews(UffdTestCase): def test_reset_disabled(self): self.login_as('admin') - valid_until = datetime.datetime.now() + datetime.timedelta(seconds=60) + valid_until = datetime.datetime.utcnow() + datetime.timedelta(seconds=60) invite = Invite(valid_until=valid_until, disabled=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() @@ -465,7 +465,7 @@ class TestInviteAdminViews(UffdTestCase): def test_reset_voided(self): self.login_as('admin') - valid_until = datetime.datetime.now() + datetime.timedelta(seconds=60) + valid_until = datetime.datetime.utcnow() + datetime.timedelta(seconds=60) invite = Invite(valid_until=valid_until, single_use=True, used=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() @@ -478,7 +478,7 @@ class TestInviteAdminViews(UffdTestCase): def test_reset_own(self): current_app.config['ACL_SIGNUP_GROUP'] = 'uffd_access' self.login_as('user') - valid_until = datetime.datetime.now() + datetime.timedelta(seconds=60) + valid_until = datetime.datetime.utcnow() + datetime.timedelta(seconds=60) invite = Invite(valid_until=valid_until, disabled=True, creator=self.get_user()) db.session.add(invite) db.session.commit() @@ -490,7 +490,7 @@ class TestInviteAdminViews(UffdTestCase): def test_reset_foreign(self): self.login_as('user') - valid_until = datetime.datetime.now() + datetime.timedelta(seconds=60) + valid_until = datetime.datetime.utcnow() + datetime.timedelta(seconds=60) role = Role(name='testrole', moderator_group=self.get_access_group()) db.session.add(role) invite = Invite(valid_until=valid_until, disabled=True, creator=self.get_admin(), roles=[role]) @@ -507,7 +507,7 @@ class TestInviteUseViews(UffdTestCase): self.app.last_mail = None def test_use(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, roles=[Role(name='testrole1'), Role(name='testrole2')]) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, roles=[Role(name='testrole1'), Role(name='testrole2')]) db.session.add(invite) db.session.commit() token = invite.token @@ -517,7 +517,7 @@ class TestInviteUseViews(UffdTestCase): def test_use_loggedin(self): self.login_as('user') - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, roles=[Role(name='testrole1'), Role(name='testrole2')]) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, roles=[Role(name='testrole1'), Role(name='testrole2')]) db.session.add(invite) db.session.commit() token = invite.token @@ -526,7 +526,7 @@ class TestInviteUseViews(UffdTestCase): self.assertEqual(r.status_code, 200) def test_use_inactive(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), disabled=True) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), disabled=True) db.session.add(invite) db.session.commit() token = invite.token @@ -548,7 +548,7 @@ class TestInviteUseViews(UffdTestCase): db.session.add(role1) role2 = Role(name='testrole2') db.session.add(role2) - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), roles=[role1, role2], creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), roles=[role1, role2], creator=self.get_admin()) db.session.add(invite) db.session.commit() invite_id = invite.id @@ -574,7 +574,7 @@ class TestInviteUseViews(UffdTestCase): self.assertIn(self.get_admin_group(), user.groups) def test_grant_invalid_invite(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), disabled=True) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), disabled=True) db.session.add(invite) db.session.commit() invite_id = invite.id @@ -586,7 +586,7 @@ class TestInviteUseViews(UffdTestCase): self.assertFalse(Invite.query.filter_by(token=token).first().used) def test_grant_no_roles(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60)) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60)) db.session.add(invite) db.session.commit() invite_id = invite.id @@ -602,7 +602,7 @@ class TestInviteUseViews(UffdTestCase): role = Role(name='testrole') db.session.add(role) user.roles.append(role) - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), roles=[role]) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), roles=[role]) db.session.add(invite) db.session.commit() invite_id = invite.id @@ -623,7 +623,7 @@ class TestInviteUseViews(UffdTestCase): db.session.add(role1) role2 = Role(name='testrole2') db.session.add(role2) - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), roles=[role1, role2], allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), roles=[role1, role2], allow_signup=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() invite_id = invite.id @@ -645,7 +645,7 @@ class TestInviteUseViews(UffdTestCase): self.assertTrue(signup.validate()[0]) def test_signup_invalid_invite(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, disabled=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, disabled=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() r = self.client.get(path=url_for('invite.signup_start', invite_id=invite.id, token=invite.token), follow_redirects=True) @@ -653,7 +653,7 @@ class TestInviteUseViews(UffdTestCase): self.assertEqual(r.status_code, 200) def test_signup_nosignup(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=False, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=False, creator=self.get_admin()) db.session.add(invite) db.session.commit() r = self.client.get(path=url_for('invite.signup_start', invite_id=invite.id, token=invite.token), follow_redirects=True) @@ -661,7 +661,7 @@ class TestInviteUseViews(UffdTestCase): self.assertEqual(r.status_code, 200) def test_signup_wrongpassword(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() r = self.client.post(path=url_for('invite.signup_submit', invite_id=invite.id, token=invite.token), @@ -671,7 +671,7 @@ class TestInviteUseViews(UffdTestCase): self.assertEqual(r.status_code, 200) def test_signup_invalid(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() r = self.client.post(path=url_for('invite.signup_submit', invite_id=invite.id, token=invite.token), @@ -682,7 +682,7 @@ class TestInviteUseViews(UffdTestCase): def test_signup_mailerror(self): self.app.config['MAIL_SKIP_SEND'] = 'fail' - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() r = self.client.post(path=url_for('invite.signup_submit', invite_id=invite.id, token=invite.token), @@ -692,7 +692,7 @@ class TestInviteUseViews(UffdTestCase): self.assertEqual(r.status_code, 200) def test_signup_hostlimit(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() invite_id = invite.id @@ -712,7 +712,7 @@ class TestInviteUseViews(UffdTestCase): self.assertIsNone(self.app.last_mail) def test_signup_mailimit(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() invite_id = invite.id @@ -732,7 +732,7 @@ class TestInviteUseViews(UffdTestCase): self.assertIsNone(self.app.last_mail) def test_signup_check(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() invite_id = invite.id @@ -744,7 +744,7 @@ class TestInviteUseViews(UffdTestCase): self.assertEqual(r.json['status'], 'ok') def test_signup_check_invalid(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() invite_id = invite.id @@ -757,7 +757,7 @@ class TestInviteUseViews(UffdTestCase): self.assertEqual(r.json['status'], 'invalid') def test_signup_check_exists(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() invite_id = invite.id @@ -769,7 +769,7 @@ class TestInviteUseViews(UffdTestCase): self.assertEqual(r.json['status'], 'exists') def test_signup_check_nosignup(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=False, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=False, creator=self.get_admin()) db.session.add(invite) db.session.commit() invite_id = invite.id @@ -781,7 +781,7 @@ class TestInviteUseViews(UffdTestCase): self.assertEqual(r.json['status'], 'error') def test_signup_check_error(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, disabled=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, disabled=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() invite_id = invite.id @@ -793,7 +793,7 @@ class TestInviteUseViews(UffdTestCase): self.assertEqual(r.json['status'], 'error') def test_signup_check_ratelimited(self): - invite = Invite(valid_until=datetime.datetime.now() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) + invite = Invite(valid_until=datetime.datetime.utcnow() + datetime.timedelta(seconds=60), allow_signup=True, creator=self.get_admin()) db.session.add(invite) db.session.commit() invite_id = invite.id diff --git a/tests/test_mfa.py b/tests/test_mfa.py index ff32a105fc9028a4f0c2ba77bfa7fe27d3590486..f1e254a3bcebe483c7a163edc4d187f4c006db94 100644 --- a/tests/test_mfa.py +++ b/tests/test_mfa.py @@ -31,7 +31,7 @@ def get_fido2_test_cred(self): class TestMfaMethodModels(UffdTestCase): def test_common_attributes(self): method = TOTPMethod(user=self.get_user(), name='testname') - self.assertTrue(method.created <= datetime.datetime.now()) + self.assertTrue(method.created <= datetime.datetime.utcnow()) self.assertEqual(method.name, 'testname') self.assertEqual(method.user.loginname, 'testuser') method.user = self.get_admin() diff --git a/tests/test_selfservice.py b/tests/test_selfservice.py index cc2b0a86a3341ab62d5a6e9deebabbde8bf46e97..760b7a449d9a30db0786201683a003f30584d7d8 100644 --- a/tests/test_selfservice.py +++ b/tests/test_selfservice.py @@ -186,7 +186,7 @@ class TestSelfservice(UffdTestCase): user = request.user old_mail = user.mail token = MailToken(user=user, newmail='newusermail@example.com', - created=(datetime.datetime.now() - datetime.timedelta(days=10))) + created=(datetime.datetime.utcnow() - datetime.timedelta(days=10))) db.session.add(token) db.session.commit() r = self.client.get(path=url_for('selfservice.token_mail', token_id=token.id, token=token.token), follow_redirects=True) @@ -288,7 +288,7 @@ class TestSelfservice(UffdTestCase): def test_token_password_expired(self): user = self.get_user() - token = PasswordToken(user=user, created=(datetime.datetime.now() - datetime.timedelta(days=10))) + token = PasswordToken(user=user, created=(datetime.datetime.utcnow() - datetime.timedelta(days=10))) db.session.add(token) db.session.commit() self.assertTrue(token.expired) diff --git a/tests/test_signup.py b/tests/test_signup.py index e77c7c4678a344a6deb826d5bfa5e87d243999e0..cfb599d5c84e6307cc0cb0910ee5921907c2c18a 100644 --- a/tests/test_signup.py +++ b/tests/test_signup.py @@ -61,7 +61,7 @@ class TestSignupModel(UffdTestCase): # TODO: Find a better way to test this! signup = Signup(loginname='newuser', displayname='New User', mail='test@example.com', password='notsecret') self.assertFalse(signup.expired) - signup.created = created=datetime.datetime.now() - datetime.timedelta(hours=49) + signup.created = created=datetime.datetime.utcnow() - datetime.timedelta(hours=49) self.assertTrue(signup.expired) def test_completed(self): @@ -86,7 +86,7 @@ class TestSignupModel(UffdTestCase): def test_validate_expired(self): signup = Signup(loginname='newuser', displayname='New User', mail='test@example.com', - password='notsecret', created=datetime.datetime.now()-datetime.timedelta(hours=49)) + password='notsecret', created=datetime.datetime.utcnow()-datetime.timedelta(hours=49)) self.assert_validate_invalid(signup) self.assert_validate_invalid(refetch_signup(signup)) @@ -132,7 +132,7 @@ class TestSignupModel(UffdTestCase): def test_finish_expired(self): # TODO: Find a better way to test this! signup = Signup(loginname='newuser', displayname='New User', mail='test@example.com', - password='notsecret', created=datetime.datetime.now()-datetime.timedelta(hours=49)) + password='notsecret', created=datetime.datetime.utcnow()-datetime.timedelta(hours=49)) self.assert_finish_failure(signup, 'notsecret') self.assert_finish_failure(refetch_signup(signup), 'notsecret') @@ -366,7 +366,7 @@ class TestSignupViews(UffdTestCase): def test_confirm_expired(self): signup = Signup(loginname='newuser', displayname='New User', mail='test@example.com', password='notsecret') - signup.created = datetime.datetime.now() - datetime.timedelta(hours=49) + signup.created = datetime.datetime.utcnow() - datetime.timedelta(hours=49) signup = refetch_signup(signup) r = self.client.get(path=url_for('signup.signup_confirm', signup_id=signup.id, token=signup.token), follow_redirects=True) dump('test_signup_confirm_expired', r) diff --git a/uffd/__init__.py b/uffd/__init__.py index d178c85f9d4e6f7f61fffe7447d83b31ca98359e..ad186dee28e1e6223661add3014988f61c3e02f4 100644 --- a/uffd/__init__.py +++ b/uffd/__init__.py @@ -4,6 +4,7 @@ import sys from flask import Flask, redirect, url_for, request, render_template from flask_babel import Babel +from babel.dates import LOCALTZ from werkzeug.exceptions import Forbidden from flask_migrate import Migrate @@ -86,7 +87,21 @@ def create_app(test_config=None): # pylint: disable=too-many-locals,too-many-sta def push_request_context(): #pylint: disable=unused-variable return {'db': db} | {name: getattr(models, name) for name in models.__all__} - babel = Babel(app) + # flask-babel requires pytz-style timezone objects, but in rare cases (e.g. + # non-IANA TZ values) LOCALTZ is stdlib-style (without normalize/localize) + if not hasattr(LOCALTZ, 'normalize'): + LOCALTZ.normalize = lambda dt: dt + if not hasattr(LOCALTZ, 'localize'): + LOCALTZ.localize = lambda dt: dt.replace(tzinfo=LOCALTZ) + + class PatchedBabel(Babel): + @property + def default_timezone(self): + if self.app.config['BABEL_DEFAULT_TIMEZONE'] == 'LOCALTZ': + return LOCALTZ + return super().default_timezone + + babel = PatchedBabel(app, default_timezone='LOCALTZ') @babel.localeselector def get_locale(): #pylint: disable=unused-variable diff --git a/uffd/migrations/versions/9f824f61d8ac_use_utc_for_datetime.py b/uffd/migrations/versions/9f824f61d8ac_use_utc_for_datetime.py new file mode 100644 index 0000000000000000000000000000000000000000..f52906178252d2b10f66ca3c797d8b5c247b26aa --- /dev/null +++ b/uffd/migrations/versions/9f824f61d8ac_use_utc_for_datetime.py @@ -0,0 +1,111 @@ +"""Use UTC for DateTime + +Revision ID: 9f824f61d8ac +Revises: a60ce68b9214 +Create Date: 2022-08-16 00:51:04.635182 + +""" +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = '9f824f61d8ac' +down_revision = 'a60ce68b9214' +branch_labels = None +depends_on = None + +import datetime + +def localtime_to_utc(dt): + return dt.astimezone(datetime.timezone.utc).replace(tzinfo=None) + +def utc_to_localtime(dt): + return dt.replace(tzinfo=datetime.timezone.utc).astimezone().replace(tzinfo=None) + +def iter_rows_paged(table, pk='id', limit=1000): + conn = op.get_bind() + pk_column = getattr(table.c, pk) + last_pk = None + while True: + expr = table.select().order_by(pk_column).limit(limit) + if last_pk is not None: + expr = expr.where(pk_column > last_pk) + result = conn.execute(expr) + pk_index = result.keys().index(pk) + rows = result.fetchall() + if not rows: + break + yield from rows + last_pk = rows[-1][pk_index] + +invite = sa.table('invite', + sa.column('id', sa.Integer), + sa.column('created', sa.DateTime), + sa.column('valid_until', sa.DateTime), +) + +password_token = sa.table('passwordToken', + sa.column('id', sa.Integer), + sa.column('created', sa.DateTime), +) + +mail_token = sa.table('mailToken', + sa.column('id', sa.Integer), + sa.column('created', sa.DateTime), +) + +device_login_initiation = sa.table('device_login_initiation', + sa.column('id', sa.Integer), + sa.column('created', sa.DateTime), +) + +signup = sa.table('signup', + sa.column('id', sa.Integer), + sa.column('created', sa.DateTime), +) + +def upgrade(): + for obj_id, created, valid_until in iter_rows_paged(invite): + op.execute(invite.update().where(invite.c.id==obj_id).values( + created=localtime_to_utc(created), + valid_until=localtime_to_utc(valid_until), + )) + for obj_id, created in iter_rows_paged(password_token): + op.execute(password_token.update().where(password_token.c.id==obj_id).values( + created=localtime_to_utc(created), + )) + for obj_id, created in iter_rows_paged(mail_token): + op.execute(mail_token.update().where(mail_token.c.id==obj_id).values( + created=localtime_to_utc(created), + )) + for obj_id, created in iter_rows_paged(device_login_initiation): + op.execute(device_login_initiation.update().where(device_login_initiation.c.id==obj_id).values( + created=localtime_to_utc(created), + )) + for obj_id, created in iter_rows_paged(signup): + op.execute(signup.update().where(signup.c.id==obj_id).values( + created=localtime_to_utc(created), + )) + +def downgrade(): + for obj_id, created, valid_until in iter_rows_paged(invite): + op.execute(invite.update().where(invite.c.id==obj_id).values( + created=utc_to_localtime(created), + valid_until=utc_to_localtime(valid_until), + )) + for obj_id, created in iter_rows_paged(password_token): + op.execute(password_token.update().where(password_token.c.id==obj_id).values( + created=utc_to_localtime(created), + )) + for obj_id, created in iter_rows_paged(mail_token): + op.execute(mail_token.update().where(mail_token.c.id==obj_id).values( + created=utc_to_localtime(created), + )) + for obj_id, created in iter_rows_paged(device_login_initiation): + op.execute(device_login_initiation.update().where(device_login_initiation.c.id==obj_id).values( + created=utc_to_localtime(created), + )) + for obj_id, created in iter_rows_paged(signup): + op.execute(signup.update().where(signup.c.id==obj_id).values( + created=utc_to_localtime(created), + )) diff --git a/uffd/models/invite.py b/uffd/models/invite.py index 12018d35ca11089c70e31da611de5d3b5060727f..ad550b256f8bba4e46f6f9eee833b319396ec2de 100644 --- a/uffd/models/invite.py +++ b/uffd/models/invite.py @@ -18,7 +18,7 @@ class Invite(db.Model): __tablename__ = 'invite' id = Column(Integer(), primary_key=True, autoincrement=True) token = Column(String(128), unique=True, nullable=False, default=token_urlfriendly) - created = Column(DateTime, default=datetime.datetime.now, nullable=False) + created = Column(DateTime, default=datetime.datetime.utcnow, nullable=False) creator_id = Column(Integer(), ForeignKey('user.id', onupdate='CASCADE'), nullable=True) creator = relationship('User') valid_until = Column(DateTime, nullable=False) @@ -32,7 +32,7 @@ class Invite(db.Model): @property def expired(self): - return datetime.datetime.now().replace(second=0, microsecond=0) > self.valid_until + return datetime.datetime.utcnow().replace(second=0, microsecond=0) > self.valid_until @property def voided(self): diff --git a/uffd/models/mfa.py b/uffd/models/mfa.py index 7db21b5cd3f97ffad9da32c4f41d931ce1b26180..9d2b3458894491c8e45ac1038b370837fc8f5239 100644 --- a/uffd/models/mfa.py +++ b/uffd/models/mfa.py @@ -29,7 +29,7 @@ class MFAMethod(db.Model): __tablename__ = 'mfa_method' id = Column(Integer(), primary_key=True, autoincrement=True) type = Column(Enum(MFAType), nullable=False) - created = Column(DateTime(), nullable=False, default=datetime.datetime.now) + created = Column(DateTime(), nullable=False, default=datetime.datetime.utcnow) name = Column(String(128)) user_id = Column(Integer(), ForeignKey('user.id', onupdate='CASCADE', ondelete='CASCADE'), nullable=False) user = relationship('User', backref=backref('mfa_methods', cascade='all, delete-orphan')) @@ -41,7 +41,7 @@ class MFAMethod(db.Model): def __init__(self, user, name=None): self.user = user self.name = name - self.created = datetime.datetime.now() + self.created = datetime.datetime.utcnow() class RecoveryCodeMethod(MFAMethod): code_salt = Column('recovery_salt', String(64)) diff --git a/uffd/models/selfservice.py b/uffd/models/selfservice.py index bb1484579e70b27f948d9b55638f25c124ef018c..5c4d5eb1079bb26ddf1ff05d5b501f58f8a1a644 100644 --- a/uffd/models/selfservice.py +++ b/uffd/models/selfservice.py @@ -13,7 +13,7 @@ class PasswordToken(db.Model): __tablename__ = 'passwordToken' id = Column(Integer(), primary_key=True, autoincrement=True) token = Column(String(128), default=token_urlfriendly, nullable=False) - created = Column(DateTime, default=datetime.datetime.now, nullable=False) + created = Column(DateTime, default=datetime.datetime.utcnow, nullable=False) user_id = Column(Integer(), ForeignKey('user.id', onupdate='CASCADE', ondelete='CASCADE'), nullable=False) user = relationship('User') @@ -21,14 +21,14 @@ class PasswordToken(db.Model): def expired(self): if self.created is None: return False - return self.created < datetime.datetime.now() - datetime.timedelta(days=2) + return self.created < datetime.datetime.utcnow() - datetime.timedelta(days=2) @cleanup_task.delete_by_attribute('expired') class MailToken(db.Model): __tablename__ = 'mailToken' id = Column(Integer(), primary_key=True, autoincrement=True) token = Column(String(128), default=token_urlfriendly, nullable=False) - created = Column(DateTime, default=datetime.datetime.now) + created = Column(DateTime, default=datetime.datetime.utcnow) user_id = Column(Integer(), ForeignKey('user.id', onupdate='CASCADE', ondelete='CASCADE'), nullable=False) user = relationship('User') newmail = Column(String(255)) @@ -37,4 +37,4 @@ class MailToken(db.Model): def expired(self): if self.created is None: return False - return self.created < datetime.datetime.now() - datetime.timedelta(days=2) + return self.created < datetime.datetime.utcnow() - datetime.timedelta(days=2) diff --git a/uffd/models/session.py b/uffd/models/session.py index 6b72912b08c0b7a068a46ad3e0932bd055f6d2c3..19fa3ad868af7cc171903692ed0ebdb805bd7974 100644 --- a/uffd/models/session.py +++ b/uffd/models/session.py @@ -80,7 +80,7 @@ class DeviceLoginInitiation(db.Model): code1 = Column(String(32), unique=True, nullable=False, default=lambda: token_typeable(3)) secret = Column(String(128), nullable=False, default=lambda: secrets.token_hex(64)) confirmations = relationship('DeviceLoginConfirmation', back_populates='initiation', cascade='all, delete-orphan') - created = Column(DateTime, default=datetime.datetime.now, nullable=False) + created = Column(DateTime, default=datetime.datetime.utcnow, nullable=False) __mapper_args__ = { 'polymorphic_on': type, @@ -96,7 +96,7 @@ class DeviceLoginInitiation(db.Model): def expired(self): if self.created is None: return False - return self.created < datetime.datetime.now() - datetime.timedelta(minutes=30) + return self.created < datetime.datetime.utcnow() - datetime.timedelta(minutes=30) @property def description(self): diff --git a/uffd/models/signup.py b/uffd/models/signup.py index 204edbc416d1c0b8c571499f12cb1a50454b6c5a..c04dbb41731db2f65c13795137018b4f5a0859b6 100644 --- a/uffd/models/signup.py +++ b/uffd/models/signup.py @@ -31,7 +31,7 @@ class Signup(db.Model): __tablename__ = 'signup' id = Column(Integer(), primary_key=True, autoincrement=True) token = Column(String(128), default=token_urlfriendly, nullable=False) - created = Column(DateTime, default=datetime.datetime.now, nullable=False) + created = Column(DateTime, default=datetime.datetime.utcnow, nullable=False) loginname = Column(Text) displayname = Column(Text) mail = Column(Text) @@ -56,7 +56,7 @@ class Signup(db.Model): def expired(self): if self.created is None: return False - return self.created < datetime.datetime.now() - datetime.timedelta(hours=48) + return self.created < datetime.datetime.utcnow() - datetime.timedelta(hours=48) @hybrid_property def completed(self): diff --git a/uffd/templates/invite/list.html b/uffd/templates/invite/list.html index 9a179a87ce7d48ac67360c8674097bbc0f103713..97c716230a7eed3730010909cdf61296649f069f 100644 --- a/uffd/templates/invite/list.html +++ b/uffd/templates/invite/list.html @@ -56,9 +56,9 @@ {% elif not invite.active %} {{_('Invalid')}} {% elif invite.single_use %} - {{ _('Valid once, expires %(expiry_date)s', expiry_date=invite.valid_until.strftime('%Y-%m-%d')) }} + {{ _('Valid once, expires %(expiry_date)s', expiry_date=invite.valid_until|dateformat) }} {% else %} - {{ _('Valid, expires %(expiry_date)s',expiry_date=invite.valid_until.strftime('%Y-%m-%d')) }} + {{ _('Valid, expires %(expiry_date)s', expiry_date=invite.valid_until|dateformat) }} {% endif %} </td> <td class="text-right"> @@ -83,8 +83,8 @@ <div class="modal-body"> <ul class="list-unstyled"> <li><b>{{_('Type:')}}</b> {% if invite.single_use %}{{_('Single-use')}}{% else %}{{_('Multi-use')}}{% endif %}</li> - <li><b>{{_('Created:')}}</b> {{ invite.created.strftime('%Y-%m-%d %H:%M:%S') }}</li> - <li><b>{{_('Expires:')}}</b> {{ invite.valid_until.strftime('%Y-%m-%d %H:%M:%S') }}</li> + <li><b>{{_('Created:')}}</b> {{ invite.created|datetimeformat }}</li> + <li><b>{{_('Expires:')}}</b> {{ invite.valid_until|datetimeformat }}</li> <li><b>{{_('Permissions:')}}</b> <ul> {% if invite.allow_signup %} diff --git a/uffd/templates/mfa/setup.html b/uffd/templates/mfa/setup.html index 5d5aefaa2be740e73c3957db6a79bb3cd179e36a..2922aac2862f5a6ebee75735d7cb8d97c040daf2 100644 --- a/uffd/templates/mfa/setup.html +++ b/uffd/templates/mfa/setup.html @@ -113,7 +113,7 @@ mfa_enabled: The user has setup at least one two-factor method. Two-factor authe {% for method in request.user.mfa_totp_methods %} <tr> <td>{{ method.name }}</td> - <td>{{ method.created.strftime('%b %d, %Y') }}</td> + <td>{{ method.created|dateformat }}</td> <td><a class="btn btn-sm btn-danger float-right" href="{{ url_for('mfa.delete_totp', id=method.id) }}">{{_("Delete")}}</a></td> </tr> {% endfor %} @@ -175,7 +175,7 @@ mfa_enabled: The user has setup at least one two-factor method. Two-factor authe {% for method in request.user.mfa_webauthn_methods %} <tr> <td>{{ method.name }}</td> - <td>{{ method.created.strftime('%b %d, %Y') }}</td> + <td>{{ method.created|dateformat }}</td> <td><a class="btn btn-sm btn-danger float-right" href="{{ url_for('mfa.delete_webauthn', id=method.id) }}">{{_("Delete")}}</a></td> </tr> {% endfor %} diff --git a/uffd/views/invite.py b/uffd/views/invite.py index 99b0675ed57ac571d90b38b13a097f170e5b1738..d05848b30e2f26abb336eeff3462b3d2e12ad65d 100644 --- a/uffd/views/invite.py +++ b/uffd/views/invite.py @@ -2,7 +2,7 @@ import datetime import secrets from flask import Blueprint, render_template, request, redirect, url_for, flash, current_app, jsonify, abort -from flask_babel import gettext as _, lazy_gettext +from flask_babel import gettext as _, lazy_gettext, to_utc import sqlalchemy from uffd.csrf import csrf_protect @@ -57,18 +57,21 @@ def new(): roles = Role.query.join(Role.moderator_group).join(Group.members).filter(User.id==request.user.id).all() return render_template('invite/new.html', roles=roles, allow_signup=allow_signup) +def parse_datetime_local_input(value): + return to_utc(datetime.datetime.fromisoformat(value)) + @bp.route('/new', methods=['POST']) @login_required(invite_acl_check) @csrf_protect(blueprint=bp) def new_submit(): invite = Invite(creator=request.user, single_use=(request.values['single-use'] == '1'), - valid_until=datetime.datetime.fromisoformat(request.values['valid-until']), + valid_until=parse_datetime_local_input(request.values['valid-until']), 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']): + if invite.valid_until > datetime.datetime.utcnow() + datetime.timedelta(days=current_app.config['INVITE_MAX_VALID_DAYS']): flash(_('The "Expires After" date is too far in the future')) return new() if not invite.permitted: diff --git a/uffd/views/session.py b/uffd/views/session.py index 3f6a6187452e79193b715953608f2d1bfa58c1d7..9e45c210220a110de38d83a91e06e9a95de7d814 100644 --- a/uffd/views/session.py +++ b/uffd/views/session.py @@ -22,7 +22,7 @@ def set_request_user(): return if 'logintime' not in session: return - if datetime.datetime.now().timestamp() > session['logintime'] + current_app.config['SESSION_LIFETIME_SECONDS']: + if datetime.datetime.utcnow().timestamp() > session['logintime'] + current_app.config['SESSION_LIFETIME_SECONDS']: return user = User.query.get(session['user_id']) if not user or not user.is_in_group(current_app.config['ACL_ACCESS_GROUP']): @@ -49,7 +49,7 @@ def set_session(user, skip_mfa=False): session.clear() session.permanent = True session['user_id'] = user.id - session['logintime'] = datetime.datetime.now().timestamp() + session['logintime'] = datetime.datetime.utcnow().timestamp() session['_csrf_token'] = secrets.token_hex(128) if skip_mfa: session['user_mfa'] = True