Project

General

Profile

issue_10.txt

Sergey Ivanovskiy, 05/22/2026 03:58 PM

Download (3.45 KB)

 
1
ISSUE DESCRIPTION:
2
*[MAJOR]* _functional_ @SsoReauth@.@handleSsoReauth@: No re-entrancy guard. Two @MSG_SSO_REAUTH@ messages in quick succession both @await cleanupReauthUi(true)@ (idempotent via @that.closed@) and both reach the @new p2j.ModalDialog('p2j-sso-reauth-dialog', ...)@ at sso_reauth.js:156. The second @new Dialog({id: that.id})@ at p2j.js:2013-2015 conflicts in the dijit registry.
3

    
4
PROPOSED FIX:
5
Add a module-scope inProgress Promise that serializes handleSsoReauth invocations. The second concurrent call awaits the first to complete before constructing its own dialog, eliminating the race window between cleanupReauthUi resolving and the new ModalDialog/dijit registration. The promise is cleared in a finally block so success and failure paths both release the lock.
6

    
7
CHANGES:
8
src/com/goldencode/p2j/ui/client/driver/web/res/p2j.sso_reauth.js
9

    
10
Before (around lines 98-160):
11
   var reauthDialog = null;
12

    
13
   /** Remaining seconds until forced logout. */
14
   var remainingSeconds = 0;
15

    
16
   ...
17

    
18
   async function handleSsoReauth(reauthUrl, reauthTimeoutSec)
19
   {
20
      if (!reauthUrl || typeof reauthUrl !== 'string')
21
      {
22
         console.error('SSO re-auth: Invalid re-auth URL');
23
         return;
24
      }
25

    
26
      const timeoutSec = (reauthTimeoutSec > 0) ? reauthTimeoutSec : 60;
27
      remainingSeconds = timeoutSec;
28

    
29
      let serverOrigin = window.location.origin;
30
      try { serverOrigin = new URL(p2j.socket.getLogoutPage()).origin; } catch(e) {}
31

    
32
      // Fully tear down any prior dialog instance (and await close) before
33
      // constructing a new one with the same dijit id.
34
      await cleanupReauthUi(true);
35

    
36
      // -- Create modal dialog for the re-auth overlay --
37
      reauthDialog = new p2j.ModalDialog('p2j-sso-reauth-dialog', document.body, '', '', true,
38
         {noTitle: true, noAutofocus: true});
39

    
40
After:
41
   var reauthDialog = null;
42

    
43
   /** Serializes concurrent handleSsoReauth invocations to prevent dijit-id collisions. */
44
   var inProgress = null;
45

    
46
   /** Remaining seconds until forced logout. */
47
   var remainingSeconds = 0;
48

    
49
   ...
50

    
51
   async function handleSsoReauth(reauthUrl, reauthTimeoutSec)
52
   {
53
      if (!reauthUrl || typeof reauthUrl !== 'string')
54
      {
55
         console.error('SSO re-auth: Invalid re-auth URL');
56
         return;
57
      }
58

    
59
      // Re-entrancy guard: if a previous handleSsoReauth is still running,
60
      // wait for it to complete before starting a new one. cleanupReauthUi
61
      // alone is not sufficient because the new ModalDialog construction
62
      // races the prior dialog's dijit-registry insertion.
63
      if (inProgress)
64
      {
65
         try { await inProgress; } catch (e) {}
66
      }
67

    
68
      inProgress = (async function()
69
      {
70
         const timeoutSec = (reauthTimeoutSec > 0) ? reauthTimeoutSec : 60;
71
         remainingSeconds = timeoutSec;
72

    
73
         let serverOrigin = window.location.origin;
74
         try { serverOrigin = new URL(p2j.socket.getLogoutPage()).origin; } catch(e) {}
75

    
76
         // Fully tear down any prior dialog instance (and await close) before
77
         // constructing a new one with the same dijit id.
78
         await cleanupReauthUi(true);
79

    
80
         // -- Create modal dialog for the re-auth overlay --
81
         reauthDialog = new p2j.ModalDialog('p2j-sso-reauth-dialog', document.body, '', '', true,
82
            {noTitle: true, noAutofocus: true});
83

    
84
         // ... rest of original body ...
85
      })();
86

    
87
      try
88
      {
89
         await inProgress;
90
      }
91
      finally
92
      {
93
         inProgress = null;
94
      }
95
   }