@@ -22,8 +22,6 @@ class PupilIdentityStreamController {
2222 final String ? importedChannelName;
2323 late String channelName;
2424
25- final String thisUserName = di <HubSessionManager >().user! .userInfo! .userName! ;
26-
2725 final _notificationService = di <NotificationService >();
2826
2927 // Controller creates and owns the state
@@ -107,6 +105,18 @@ class PupilIdentityStreamController {
107105 }
108106 }
109107
108+ /// Validate user session before sending a message to prevent null sender
109+ String ? _validateUserSession () {
110+ final currentUser = di <HubSessionManager >().user? .userInfo? .userName;
111+ if (currentUser == null || currentUser.isEmpty) {
112+ _log.severe (
113+ 'Cannot send message: username is null or empty. User session may have expired.' ,
114+ );
115+ return null ;
116+ }
117+ return currentUser;
118+ }
119+
110120 /// Reset sender state for new requests
111121 void resetSenderForNewRequest () {
112122 if (_isDisposed) {
@@ -147,11 +157,20 @@ class PupilIdentityStreamController {
147157 // Update local state to transmitting
148158 _handleRequestConfirmed ();
149159
160+ // Validate user session before sending
161+ final validatedSender = _validateUserSession ();
162+ if (validatedSender == null ) {
163+ _log.severe (
164+ 'Cannot confirm transfer for $userName : invalid user session' ,
165+ );
166+ return ;
167+ }
168+
150169 // Notify receiver of confirmation (backward compatibility)
151170 await di <Client >().pupilIdentity.sendPupilIdentityMessage (
152171 channelName,
153172 PupilIdentityDto (
154- sender: thisUserName ,
173+ sender: validatedSender ,
155174 type: 'confirmed' ,
156175 value: userName,
157176 ),
@@ -161,7 +180,7 @@ class PupilIdentityStreamController {
161180 await di <Client >().pupilIdentity.sendPupilIdentityMessage (
162181 channelName,
163182 PupilIdentityDto (
164- sender: thisUserName ,
183+ sender: validatedSender ,
165184 type: 'data' ,
166185 dataTimeStamp: di <EnvManager >().activeEnv? .lastIdentitiesUpdate,
167186 value: '$userName :${dataToSend ?? '' }' ,
@@ -207,6 +226,13 @@ class PupilIdentityStreamController {
207226 String userName, {
208227 bool isAutoRejection = false ,
209228 }) async {
229+ // Validate user session before sending
230+ final validatedSender = _validateUserSession ();
231+ if (validatedSender == null ) {
232+ _log.severe ('Cannot send rejection to $userName : invalid user session' );
233+ return ;
234+ }
235+
210236 final rejectionValue = isAutoRejection ? 'auto:$userName ' : userName;
211237 int retryCount = 0 ;
212238 const maxRetries = 3 ;
@@ -220,7 +246,7 @@ class PupilIdentityStreamController {
220246 await di <Client >().pupilIdentity.sendPupilIdentityMessage (
221247 channelName,
222248 PupilIdentityDto (
223- sender: thisUserName ,
249+ sender: validatedSender ,
224250 type: 'rejected' ,
225251 value: rejectionValue,
226252 ),
@@ -314,14 +340,21 @@ class PupilIdentityStreamController {
314340 void _sendReceiverMessages () {
315341 _log.info ('Receiver sending joined message and data request...' );
316342
343+ // Validate user session before sending
344+ final validatedSender = _validateUserSession ();
345+ if (validatedSender == null ) {
346+ _log.severe ('Cannot send receiver messages: invalid user session' );
347+ return ;
348+ }
349+
317350 // First send joined message
318351 di <Client >().pupilIdentity
319352 .sendPupilIdentityMessage (
320353 channelName,
321354 PupilIdentityDto (
322- sender: thisUserName ,
355+ sender: validatedSender ,
323356 type: 'joined' ,
324- value: thisUserName ,
357+ value: validatedSender ,
325358 ),
326359 )
327360 .then ((_) {
@@ -345,9 +378,9 @@ class PupilIdentityStreamController {
345378 return di <Client >().pupilIdentity.sendPupilIdentityMessage (
346379 channelName,
347380 PupilIdentityDto (
348- sender: thisUserName ,
381+ sender: validatedSender ,
349382 type: 'request' ,
350- value: thisUserName ,
383+ value: validatedSender ,
351384 ),
352385 );
353386 })
@@ -557,17 +590,21 @@ class PupilIdentityStreamController {
557590 // If receiver is leaving, send close message before disposing
558591 if (role == PupilIdentityStreamRole .receiver &&
559592 state.streamState.isConnected.value) {
560- // Send close message and ignore errors since we're disposing
561- di <Client >().pupilIdentity
562- .sendPupilIdentityMessage (
563- channelName,
564- PupilIdentityDto (
565- sender: thisUserName,
566- type: 'close' ,
567- value: thisUserName,
568- ),
569- )
570- .ignore ();
593+ // Validate user session before sending
594+ final validatedSender = _validateUserSession ();
595+ if (validatedSender != null ) {
596+ // Send close message and ignore errors since we're disposing
597+ di <Client >().pupilIdentity
598+ .sendPupilIdentityMessage (
599+ channelName,
600+ PupilIdentityDto (
601+ sender: validatedSender,
602+ type: 'close' ,
603+ value: validatedSender,
604+ ),
605+ )
606+ .ignore ();
607+ }
571608 }
572609
573610 _subscription? .cancel ();
@@ -581,43 +618,50 @@ class PupilIdentityStreamController {
581618 }
582619
583620 void stopStream () async {
621+ // Validate user session before sending any messages
622+ final validatedSender = _validateUserSession ();
623+
584624 // If sender is shutting down, notify all receivers
585625 if (role == PupilIdentityStreamRole .sender &&
586626 state.streamState.isConnected.value) {
587- try {
588- // Send shutdown message to all connected receivers
589- await di <Client >().pupilIdentity.sendPupilIdentityMessage (
590- channelName,
591- PupilIdentityDto (
592- sender: thisUserName,
593- type: 'shutdown' ,
594- value: 'Sender hat den Stream beendet' ,
595- ),
596- );
597- _log.info ('Sent shutdown message to all receivers' );
627+ if (validatedSender != null ) {
628+ try {
629+ // Send shutdown message to all connected receivers
630+ await di <Client >().pupilIdentity.sendPupilIdentityMessage (
631+ channelName,
632+ PupilIdentityDto (
633+ sender: validatedSender,
634+ type: 'shutdown' ,
635+ value: 'Sender hat den Stream beendet' ,
636+ ),
637+ );
638+ _log.info ('Sent shutdown message to all receivers' );
598639
599- // Wait a brief moment to ensure message is sent
600- await Future .delayed (const Duration (milliseconds: 200 ));
601- } catch (e) {
602- _log.warning ('Failed to send shutdown message: $e ' );
640+ // Wait a brief moment to ensure message is sent
641+ await Future .delayed (const Duration (milliseconds: 200 ));
642+ } catch (e) {
643+ _log.warning ('Failed to send shutdown message: $e ' );
644+ }
603645 }
604646 }
605647
606648 // If receiver is leaving, send close message to notify sender
607649 if (role == PupilIdentityStreamRole .receiver &&
608650 state.streamState.isConnected.value) {
609- try {
610- await di <Client >().pupilIdentity.sendPupilIdentityMessage (
611- channelName,
612- PupilIdentityDto (
613- sender: thisUserName,
614- type: 'close' ,
615- value: thisUserName,
616- ),
617- );
618- _log.info ('Sent close message to sender before leaving' );
619- } catch (e) {
620- _log.warning ('Failed to send close message: $e ' );
651+ if (validatedSender != null ) {
652+ try {
653+ await di <Client >().pupilIdentity.sendPupilIdentityMessage (
654+ channelName,
655+ PupilIdentityDto (
656+ sender: validatedSender,
657+ type: 'close' ,
658+ value: validatedSender,
659+ ),
660+ );
661+ _log.info ('Sent close message to sender before leaving' );
662+ } catch (e) {
663+ _log.warning ('Failed to send close message: $e ' );
664+ }
621665 }
622666 }
623667
0 commit comments