From 23c9828fed5117fbb53a15672abcd0588c2a4bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20Papp?= Date: Thu, 30 Jul 2026 21:00:27 +0200 Subject: [PATCH] [client] Read the extend flow's config and hint path in one lock extendAuthSession took the config from stateSnapshot and the config path from a second call, each acquiring the lock on its own. A profile switch landing between the two swaps every field, which would authenticate with one profile's config while reading the login hint from another profile's account file. Replace configPathSnapshot with authSnapshot, which returns both from a single critical section. --- client/android/client.go | 8 ++++++-- client/android/session.go | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/client/android/client.go b/client/android/client.go index 84ed622ae..e171af5c9 100644 --- a/client/android/client.go +++ b/client/android/client.go @@ -113,10 +113,14 @@ func (c *Client) stateSnapshot() (*profilemanager.Config, string, *internal.Conn return c.config, c.cacheDir, c.connectClient } -func (c *Client) configPathSnapshot() string { +// authSnapshot returns the config together with the path it was loaded from, in +// one lock: the path identifies the profile whose account email backs the login +// hint, so reading it separately could pair one profile's config with another's +// hint when a profile switch lands in between. +func (c *Client) authSnapshot() (*profilemanager.Config, string, *internal.ConnectClient) { c.stateMu.RLock() defer c.stateMu.RUnlock() - return c.cfgPath + return c.config, c.cfgPath, c.connectClient } func (c *Client) getConnectClient() *internal.ConnectClient { diff --git a/client/android/session.go b/client/android/session.go index b1bb6a3e7..d5da09c93 100644 --- a/client/android/session.go +++ b/client/android/session.go @@ -278,7 +278,7 @@ func (c *Client) endExtend() { } func (c *Client) extendAuthSession(ctx context.Context, urlOpener URLOpener, isAndroidTV bool) error { - cfg, _, cc := c.stateSnapshot() + cfg, cfgPath, cc := c.authSnapshot() if cfg == nil || cc == nil { return fmt.Errorf("engine is not running") } @@ -296,7 +296,7 @@ func (c *Client) extendAuthSession(ctx context.Context, urlOpener URLOpener, isA // Passing the config path makes the flow pick up the login_hint: an extend // renews the session of the account already signed in, so it must not stop to // offer a choice. - a := NewAuthWithConfig(ctx, cfg, c.configPathSnapshot()) + a := NewAuthWithConfig(ctx, cfg, cfgPath) tokenInfo, err := a.foregroundGetTokenInfo(authClient, urlOpener, isAndroidTV) if err != nil { return fmt.Errorf("interactive sso login failed: %v", err)