3737
3838
3939class ScheduleMixin :
40+ MY_STARRED_ICS_TOKEN_SESSION_KEY = 'my_starred_ics_token'
4041 @cached_property
4142 def version (self ):
4243 if version := self .kwargs .get ("version" ):
@@ -69,19 +70,27 @@ def dispatch(self, request, *args, **kwargs):
6970 return super ().dispatch (request , * args , ** kwargs )
7071
7172 @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 )
7582 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
7788
7889 @staticmethod
7990 def parse_ics_token (token ):
8091 """Parse and validate the token, return user_id if valid"""
8192 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 )
8594 return value ["user_id" ]
8695 except (signing .BadSignature , signing .SignatureExpired , KeyError , ValueError ) as e :
8796 logger .warning ('Failed to parse ICS token: %s' , e )
@@ -97,10 +106,10 @@ def check_token_expiry(token):
97106 - True if token is valid and not expiring soon (>= 4 days)
98107 """
99108 try :
100- value = signing .loads (token , salt = "my-starred-ics" )
109+ value = signing .loads (token , salt = "my-starred-ics" , max_age = 5 * 60 )
101110 expiry_date = timezone .datetime .fromtimestamp (value ["exp" ], tz = timezone .utc )
102111 time_until_expiry = expiry_date - timezone .now ()
103- return time_until_expiry >= timedelta (days = 4 )
112+ return time_until_expiry >= timedelta (minutes = 1 )
104113 except Exception as e :
105114 logger .warning ('Failed to check token expiry: %s' , e )
106115 return None # Invalid token
@@ -357,7 +366,6 @@ class ChangelogView(EventPermissionRequired, TemplateView):
357366
358367class CalendarRedirectView (EventPermissionRequired , ScheduleMixin , TemplateView ):
359368 """Handles redirects for both Google Calendar and other calendar applications"""
360- MY_STARRED_ICS_TOKEN_SESSION_KEY = 'my_starred_ics_token'
361369 permission_required = "agenda.view_schedule"
362370
363371 def get (self , request , * args , ** kwargs ):
@@ -371,7 +379,8 @@ def get(self, request, *args, **kwargs):
371379 if is_my :
372380 # For starred sessions
373381 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 )
375384
376385 # Check for existing valid token
377386 existing_token = request .session .get (self .MY_STARRED_ICS_TOKEN_SESSION_KEY )
@@ -380,14 +389,13 @@ def get(self, request, *args, **kwargs):
380389 # If we have an existing token, check if it's still valid and not expiring soon
381390 if existing_token :
382391 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
384393 token = existing_token
385394 generate_new_token = False
386395
387- # Generate new token if needed
396+ # Generate new token if needed (this will invalidate any existing token)
388397 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 )
391399
392400 # Build tokenized URL for starred sessions
393401 ics_url = request .build_absolute_uri (
0 commit comments