37
37
38
38
39
39
class ScheduleMixin :
40
+ MY_STARRED_ICS_TOKEN_SESSION_KEY = 'my_starred_ics_token'
40
41
@cached_property
41
42
def version (self ):
42
43
if version := self .kwargs .get ("version" ):
@@ -69,19 +70,27 @@ def dispatch(self, request, *args, **kwargs):
69
70
return super ().dispatch (request , * args , ** kwargs )
70
71
71
72
@staticmethod
72
- def generate_ics_token (user_id ):
73
- """Generate a signed token with user ID and 15-day expiry"""
74
- expiry = timezone .now () + timedelta (days = 15 )
73
+ def generate_ics_token (request , user_id ):
74
+ """Generate a signed token with user ID and 15-day expiry, invalidating previous tokens"""
75
+ # Clear any existing token from the session
76
+ key = ScheduleMixin .MY_STARRED_ICS_TOKEN_SESSION_KEY
77
+ if key in request .session :
78
+ del request .session [key ]
79
+
80
+ # Generate new token
81
+ expiry = timezone .now () + timedelta (minutes = 5 )
75
82
value = {"user_id" : user_id , "exp" : int (expiry .timestamp ())}
76
- return signing .dumps (value , salt = "my-starred-ics" )
83
+ token = signing .dumps (value , salt = "my-starred-ics" )
84
+
85
+ # Store new token in session
86
+ request .session [key ] = token
87
+ return token
77
88
78
89
@staticmethod
79
90
def parse_ics_token (token ):
80
91
"""Parse and validate the token, return user_id if valid"""
81
92
try :
82
- value = signing .loads (token , salt = "my-starred-ics" , max_age = 15 * 24 * 60 * 60 )
83
- if value ["exp" ] < int (timezone .now ().timestamp ()):
84
- raise ValueError ("Token expired" )
93
+ value = signing .loads (token , salt = "my-starred-ics" , max_age = 5 * 60 )
85
94
return value ["user_id" ]
86
95
except (signing .BadSignature , signing .SignatureExpired , KeyError , ValueError ) as e :
87
96
logger .warning ('Failed to parse ICS token: %s' , e )
@@ -97,10 +106,10 @@ def check_token_expiry(token):
97
106
- True if token is valid and not expiring soon (>= 4 days)
98
107
"""
99
108
try :
100
- value = signing .loads (token , salt = "my-starred-ics" )
109
+ value = signing .loads (token , salt = "my-starred-ics" , max_age = 5 * 60 )
101
110
expiry_date = timezone .datetime .fromtimestamp (value ["exp" ], tz = timezone .utc )
102
111
time_until_expiry = expiry_date - timezone .now ()
103
- return time_until_expiry >= timedelta (days = 4 )
112
+ return time_until_expiry >= timedelta (minutes = 1 )
104
113
except Exception as e :
105
114
logger .warning ('Failed to check token expiry: %s' , e )
106
115
return None # Invalid token
@@ -357,7 +366,6 @@ class ChangelogView(EventPermissionRequired, TemplateView):
357
366
358
367
class CalendarRedirectView (EventPermissionRequired , ScheduleMixin , TemplateView ):
359
368
"""Handles redirects for both Google Calendar and other calendar applications"""
360
- MY_STARRED_ICS_TOKEN_SESSION_KEY = 'my_starred_ics_token'
361
369
permission_required = "agenda.view_schedule"
362
370
363
371
def get (self , request , * args , ** kwargs ):
@@ -371,7 +379,8 @@ def get(self, request, *args, **kwargs):
371
379
if is_my :
372
380
# For starred sessions
373
381
if not request .user .is_authenticated :
374
- return HttpResponseRedirect (self .request .event .urls .login )
382
+ login_url = f"{ self .request .event .urls .login } ?next={ request .get_full_path ()} "
383
+ return HttpResponseRedirect (login_url )
375
384
376
385
# Check for existing valid token
377
386
existing_token = request .session .get (self .MY_STARRED_ICS_TOKEN_SESSION_KEY )
@@ -380,14 +389,13 @@ def get(self, request, *args, **kwargs):
380
389
# If we have an existing token, check if it's still valid and not expiring soon
381
390
if existing_token :
382
391
token_status = self .check_token_expiry (existing_token )
383
- if token_status is True :
392
+ if token_status is True : # Token is valid and has at least 4 days left
384
393
token = existing_token
385
394
generate_new_token = False
386
395
387
- # Generate new token if needed
396
+ # Generate new token if needed (this will invalidate any existing token)
388
397
if generate_new_token :
389
- token = self .generate_ics_token (request .user .id )
390
- request .session [self .MY_STARRED_ICS_TOKEN_SESSION_KEY ] = token
398
+ token = self .generate_ics_token (request , request .user .id )
391
399
392
400
# Build tokenized URL for starred sessions
393
401
ics_url = request .build_absolute_uri (
0 commit comments