From b8c89c43dfcd69bd84ab7bdc00d587e149393f02 Mon Sep 17 00:00:00 2001 From: Ronni Skansing Date: Thu, 14 May 2026 11:09:14 +0200 Subject: [PATCH] fix keepAlive cant be ovewritten with refresh from recipient Signed-off-by: Ronni Skansing --- backend/controller/remoteBrowser.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/backend/controller/remoteBrowser.go b/backend/controller/remoteBrowser.go index 10db858..ecdd8a6 100644 --- a/backend/controller/remoteBrowser.go +++ b/backend/controller/remoteBrowser.go @@ -43,6 +43,10 @@ type activeSession struct { CRID uuid.UUID CreatedAt time.Time victimConnected atomic.Bool + // isKeepAlive is set when the JS script calls s.keepAlive(), meaning the + // browser is parked and available for operator takeover. A revisit from the + // victim must not cancel this session. + isKeepAlive atomic.Bool // browserPage is set (non-nil) only after newSession() is called. browserPageMu sync.Mutex browserPage *rod.Page @@ -456,9 +460,19 @@ func (m *RemoteBrowserController) ServeVictim(g *gin.Context) { sess.victimConnected.Store(true) // One active session per campaign recipient — cancel any previous one. + // Exception: if the previous session is in keepAlive state the script has + // parked and is waiting for operator takeover; cancelling it would destroy + // a live browser the operator may be about to use. In that case put the + // old session back and drop the new connection instead. crIDStr := crID.String() if prev, hadPrev := m.activeSessions.Swap(crIDStr, sess); hadPrev { - prev.(*activeSession).cancel() + prevSess := prev.(*activeSession) + if prevSess.isKeepAlive.Load() { + m.activeSessions.Store(crIDStr, prevSess) + cancel() + return + } + prevSess.cancel() } defer func() { m.activeSessions.CompareAndDelete(crIDStr, sess) @@ -612,6 +626,7 @@ func (m *RemoteBrowserController) ServeVictim(g *gin.Context) { m.saveInfoEvent(g.Request.Context(), &campaignID, &recipientID, evt.Message, clientIP, userAgent) } if evt.Type == "keep_alive" { + sess.isKeepAlive.Store(true) select { case page := <-runner.LiveCh: sess.setBrowserPage(page)