Skip to content

Commit 686a915

Browse files
Merge remote-tracking branch 'origin/main' into personal/jennifer/7.45.1.dev0.bootstrap-merge
# Conflicts: # ietf/templates/meeting/session_buttons_include.html
2 parents 5be2774 + 6968252 commit 686a915

21 files changed

Lines changed: 276 additions & 94 deletions

File tree

changelog

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,38 @@
1+
ietfdb (7.46.0) ietf; urgency=medium
2+
3+
** bugfixes, security improvements, performance improvements **
4+
5+
* Merged in [19946] from rjsparks@nostrum.com:
6+
Allow the secretariat to request many more sessions.
7+
8+
* Merged in [19947] from rjsparks@nostrum.com:
9+
Add link to onsite tool to agenda. Fixes #3550.
10+
11+
* Merged in [19948] from rjsparks@nostrum.com:
12+
Update link to handling ballot positions. Fixes #3208.
13+
14+
* Merged in [19949] and [19950] from rjsparks@nostrum.com:
15+
Use tempfiles while rebuilding group and doc alias files. Fixes #3521.
16+
17+
* Merged in [19952] from rjsparks@nostrum.com:
18+
Only keep the first and most recent yang validator SubmissionCheck for
19+
any given submission. Fixes #3542.
20+
21+
* Merged in [19954] from jennifer@painless-security.com:
22+
Refactor session overlap computation to treat overlapping sessions
23+
correctly.
24+
25+
* Merged in [19967] from rjsparks@nostrum.com:
26+
From Kesara Rathnayake: Expire password reset links on use, password
27+
change through other mechanics, login, or a short configurable time
28+
(initially one hour).
29+
30+
* Merged in [19969] from jennifer@painless-security.com:
31+
Use correct UTC time when creating Meetecho conferences. Fixes #3565.
32+
33+
-- Robert Sparks <rjsparks@nostrum.com> 24 Feb 2022 03:05:28 +0000
34+
35+
136
ietfdb (7.45.0) ietf; urgency=medium
237

338
** MeetEcho interim request integration, bugfixes **

hold-for-merge

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
# Everyting below this line is OBE
88

9+
/personal/rjs/7.45.1.dev0@19962 # Mangled commit
910
/personal/rjs/7.39.1.dev1@19554 # Optimization wasn't measured correctly
1011
/personal/rjs/7.36.1.dev0@19318 # Folded this into r19336
1112
/personal/rjs/7.36.1.dev0@19302 # Handled this in an earlier merge

ietf/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
from . import checks # pyflakes:ignore
66

77
# Don't add patch number here:
8-
__version__ = "7.45.1.dev0"
8+
__version__ = "7.46.1.dev0"
99

1010
# set this to ".p1", ".p2", etc. after patching
1111
__patch__ = ""
1212

1313
__date__ = "$Date$"
1414

15-
__rev__ = "$Rev$ (dev) Latest release: Rev. 19938 "
15+
__rev__ = "$Rev$ (dev) Latest release: Rev. 19974 "
1616

1717
__id__ = "$Id$"

ietf/doc/management/commands/generate_draft_aliases.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
import io
99
import os
1010
import re
11+
import shutil
12+
import stat
1113
import time
14+
15+
from tempfile import mkstemp
1216

1317
from django.conf import settings
1418
from django.core.management.base import BaseCommand
@@ -102,8 +106,13 @@ def handle(self, *args, **options):
102106
date = time.strftime("%Y-%m-%d_%H:%M:%S")
103107
signature = '# Generated by %s at %s\n' % (os.path.abspath(__file__), date)
104108

105-
afile = io.open(settings.DRAFT_ALIASES_PATH, "w")
106-
vfile = io.open(settings.DRAFT_VIRTUAL_PATH, "w")
109+
ahandle, aname = mkstemp()
110+
os.close(ahandle)
111+
afile = io.open(aname,"w")
112+
113+
vhandle, vname = mkstemp()
114+
os.close(vhandle)
115+
vfile = io.open(vname,"w")
107116

108117
afile.write(signature)
109118
vfile.write(signature)
@@ -160,4 +169,11 @@ def handle(self, *args, **options):
160169

161170
afile.close()
162171
vfile.close()
172+
173+
os.chmod(aname, stat.S_IWUSR|stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH)
174+
os.chmod(vname, stat.S_IWUSR|stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH)
175+
176+
shutil.move(aname, settings.DRAFT_ALIASES_PATH)
177+
shutil.move(vname, settings.DRAFT_VIRTUAL_PATH)
178+
163179

ietf/group/management/commands/generate_group_aliases.py

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77
import datetime
88
import io
99
import os
10+
import shutil
11+
import stat
1012
import time
13+
14+
from tempfile import mkstemp
1115

1216
from django.conf import settings
1317
from django.core.management.base import BaseCommand
@@ -40,8 +44,13 @@ def handle(self, *args, **options):
4044
date = time.strftime("%Y-%m-%d_%H:%M:%S")
4145
signature = '# Generated by %s at %s\n' % (os.path.abspath(__file__), date)
4246

43-
afile = io.open(settings.GROUP_ALIASES_PATH, "w")
44-
vfile = io.open(settings.GROUP_VIRTUAL_PATH, "w")
47+
ahandle, aname = mkstemp()
48+
os.close(ahandle)
49+
afile = io.open(aname,"w")
50+
51+
vhandle, vname = mkstemp()
52+
os.close(vhandle)
53+
vfile = io.open(vname,"w")
4554

4655
afile.write(signature)
4756
vfile.write(signature)
@@ -86,4 +95,10 @@ def handle(self, *args, **options):
8695
dump_sublist(afile, vfile, group.acronym+'-chairs', IETF_DOMAIN, settings.GROUP_VIRTUAL_DOMAIN, get_group_role_emails(group, ['chair', 'delegate']))
8796

8897
afile.close()
89-
vfile.close()
98+
vfile.close()
99+
100+
os.chmod(aname, stat.S_IWUSR|stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH)
101+
os.chmod(vname, stat.S_IWUSR|stat.S_IRUSR|stat.S_IRGRP|stat.S_IROTH)
102+
103+
shutil.move(aname, settings.GROUP_ALIASES_PATH)
104+
shutil.move(vname, settings.GROUP_VIRTUAL_PATH)

ietf/ietfauth/tests.py

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -373,9 +373,11 @@ def test_nomcom_dressing_on_profile(self):
373373

374374
def test_reset_password(self):
375375
url = urlreverse(ietf.ietfauth.views.password_reset)
376+
email = 'someone@example.com'
377+
password = 'foobar'
376378

377-
user = User.objects.create(username="someone@example.com", email="someone@example.com")
378-
user.set_password("forgotten")
379+
user = User.objects.create(username=email, email=email)
380+
user.set_password(password)
379381
user.save()
380382
p = Person.objects.create(name="Some One", ascii="Some One", user=user)
381383
Email.objects.create(address=user.username, person=p, origin=user.username)
@@ -414,6 +416,39 @@ def test_reset_password(self):
414416
self.assertEqual(len(q("form .is-invalid")), 0)
415417
self.assertTrue(self.username_in_htpasswd_file(user.username))
416418

419+
# reuse reset url
420+
r = self.client.get(confirm_url)
421+
self.assertEqual(r.status_code, 404)
422+
423+
# login after reset request
424+
empty_outbox()
425+
user.set_password(password)
426+
user.save()
427+
428+
r = self.client.post(url, { 'username': user.username })
429+
self.assertEqual(r.status_code, 200)
430+
self.assertEqual(len(outbox), 1)
431+
confirm_url = self.extract_confirm_url(outbox[-1])
432+
433+
r = self.client.post(urlreverse(ietf.ietfauth.views.login), {'username': email, 'password': password})
434+
435+
r = self.client.get(confirm_url)
436+
self.assertEqual(r.status_code, 404)
437+
438+
# change password after reset request
439+
empty_outbox()
440+
441+
r = self.client.post(url, { 'username': user.username })
442+
self.assertEqual(r.status_code, 200)
443+
self.assertEqual(len(outbox), 1)
444+
confirm_url = self.extract_confirm_url(outbox[-1])
445+
446+
user.set_password('newpassword')
447+
user.save()
448+
449+
r = self.client.get(confirm_url)
450+
self.assertEqual(r.status_code, 404)
451+
417452
def test_review_overview(self):
418453
review_req = ReviewRequestFactory()
419454
assignment = ReviewAssignmentFactory(review_request=review_req,reviewer=EmailFactory(person__user__username='reviewer'))

ietf/ietfauth/views.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636

3737
import importlib
3838

39-
from datetime import date as Date
39+
from datetime import date as Date, datetime as DateTime
4040
# needed if we revert to higher barrier for account creation
4141
#from datetime import datetime as DateTime, timedelta as TimeDelta, date as Date
4242
from collections import defaultdict
@@ -418,7 +418,16 @@ def password_reset(request):
418418
if form.is_valid():
419419
username = form.cleaned_data['username']
420420

421-
auth = django.core.signing.dumps(username, salt="password_reset")
421+
data = { 'username': username }
422+
if User.objects.filter(username=username).exists():
423+
user = User.objects.get(username=username)
424+
data['password'] = user.password and user.password[-4:]
425+
if user.last_login:
426+
data['last_login'] = user.last_login.timestamp()
427+
else:
428+
data['last_login'] = None
429+
430+
auth = django.core.signing.dumps(data, salt="password_reset")
422431

423432
domain = Site.objects.get_current().domain
424433
subject = 'Confirm password reset at %s' % domain
@@ -429,7 +438,7 @@ def password_reset(request):
429438
'domain': domain,
430439
'auth': auth,
431440
'username': username,
432-
'expire': settings.DAYS_TO_EXPIRE_REGISTRATION_LINK,
441+
'expire': settings.MINUTES_TO_EXPIRE_RESET_PASSWORD_LINK,
433442
})
434443

435444
success = True
@@ -443,11 +452,16 @@ def password_reset(request):
443452

444453
def confirm_password_reset(request, auth):
445454
try:
446-
username = django.core.signing.loads(auth, salt="password_reset", max_age=settings.DAYS_TO_EXPIRE_REGISTRATION_LINK * 24 * 60 * 60)
455+
data = django.core.signing.loads(auth, salt="password_reset", max_age=settings.MINUTES_TO_EXPIRE_RESET_PASSWORD_LINK * 60)
456+
username = data['username']
457+
password = data['password']
458+
last_login = None
459+
if data['last_login']:
460+
last_login = DateTime.fromtimestamp(data['last_login'])
447461
except django.core.signing.BadSignature:
448462
raise Http404("Invalid or expired auth")
449463

450-
user = get_object_or_404(User, username=username)
464+
user = get_object_or_404(User, username=username, password__endswith=password, last_login=last_login)
451465

452466
success = False
453467
if request.method == 'POST':

ietf/meeting/helpers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1099,7 +1099,7 @@ def create_interim_session_conferences(sessions):
10991099
confs = meetecho_manager.create(
11001100
group=session.group,
11011101
description=str(session),
1102-
start_time=ts.time,
1102+
start_time=ts.utc_start_time(),
11031103
duration=ts.duration,
11041104
)
11051105
except Exception as err:

ietf/meeting/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,6 +487,9 @@ def audio_stream_url(self):
487487
def video_stream_url(self):
488488
urlresources = [ur for ur in self.urlresource_set.all() if ur.name_id in ['meetecho']]
489489
return urlresources[0].url if urlresources else None
490+
def onsite_tool_url(self):
491+
urlresources = [ur for ur in self.urlresource_set.all() if ur.name_id in ['meetecho_onsite']]
492+
return urlresources[0].url if urlresources else None
490493
def webex_url(self):
491494
urlresources = [ur for ur in self.urlresource_set.all() if ur.name_id in ['webex']]
492495
return urlresources[0].url if urlresources else None

ietf/meeting/tests_helpers.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -456,8 +456,8 @@ def test_sessions_post_cancel_delete_exception(self, mock):
456456
def test_create_interim_session_conferences(self, mock):
457457
mock_conf_mgr = mock.return_value # "instance" seen by the internals
458458
sessions = [
459-
SessionFactory(meeting__type_id='interim', remote_instructions='junk'),
460-
SessionFactory(meeting__type_id='interim', remote_instructions=''),
459+
SessionFactory(meeting__type_id='interim', meeting__time_zone='america/halifax', remote_instructions='junk'),
460+
SessionFactory(meeting__type_id='interim', meeting__time_zone='asia/kuala_lumpur', remote_instructions=''),
461461
]
462462
timeslots = [
463463
session.official_timeslotassignment().timeslot for session in sessions
@@ -482,18 +482,18 @@ def test_create_interim_session_conferences(self, mock):
482482
mock_conf_mgr.create.return_value = [
483483
Conference(
484484
manager=mock_conf_mgr, id=1, public_id='some-uuid', description='desc',
485-
start_time=timeslots[0].time, duration=timeslots[0].duration, url='fake-meetecho-url',
485+
start_time=timeslots[0].utc_start_time(), duration=timeslots[0].duration, url='fake-meetecho-url',
486486
deletion_token='please-delete-me',
487487
),
488488
]
489489
create_interim_session_conferences([sessions[0]])
490490
self.assertTrue(mock_conf_mgr.create.called)
491-
self.assertCountEqual(
491+
self.assertEqual(
492492
mock_conf_mgr.create.call_args[1],
493493
{
494494
'group': sessions[0].group,
495495
'description': str(sessions[0]),
496-
'start_time': timeslots[0].time,
496+
'start_time': timeslots[0].utc_start_time(),
497497
'duration': timeslots[0].duration,
498498
}
499499
)
@@ -507,30 +507,30 @@ def test_create_interim_session_conferences(self, mock):
507507
mock_conf_mgr.create.side_effect = [
508508
[Conference(
509509
manager=mock_conf_mgr, id=1, public_id='some-uuid', description='desc',
510-
start_time=timeslots[0].time, duration=timeslots[0].duration, url='different-fake-meetecho-url',
510+
start_time=timeslots[0].utc_start_time(), duration=timeslots[0].duration, url='different-fake-meetecho-url',
511511
deletion_token='please-delete-me',
512512
)],
513513
[Conference(
514514
manager=mock_conf_mgr, id=2, public_id='another-uuid', description='desc',
515-
start_time=timeslots[1].time, duration=timeslots[1].duration, url='another-fake-meetecho-url',
515+
start_time=timeslots[1].utc_start_time(), duration=timeslots[1].duration, url='another-fake-meetecho-url',
516516
deletion_token='please-delete-me-too',
517517
)],
518518
]
519519
create_interim_session_conferences([sessions[0], sessions[1]])
520520
self.assertTrue(mock_conf_mgr.create.called)
521-
self.assertCountEqual(
521+
self.assertEqual(
522522
mock_conf_mgr.create.call_args_list,
523523
[
524524
({
525525
'group': sessions[0].group,
526526
'description': str(sessions[0]),
527-
'start_time': timeslots[0].time,
527+
'start_time': timeslots[0].utc_start_time(),
528528
'duration': timeslots[0].duration,
529529
},),
530530
({
531531
'group': sessions[1].group,
532532
'description': str(sessions[1]),
533-
'start_time': timeslots[1].time,
533+
'start_time': timeslots[1].utc_start_time(),
534534
'duration': timeslots[1].duration,
535535
},),
536536
]

0 commit comments

Comments
 (0)