Add potential hacky workaround for multiple devices in gaia pairing

This commit is contained in:
Tulir Asokan 2024-04-11 15:46:07 +03:00
parent c82a38b662
commit 86f06804b8
3 changed files with 35 additions and 15 deletions

View file

@ -78,6 +78,8 @@ type Client struct {
conversationsFetchedOnce bool conversationsFetchedOnce bool
GaiaHackyDeviceSwitcher int
AuthData *AuthData AuthData *AuthData
cfg *gmproto.Config cfg *gmproto.Config

View file

@ -244,9 +244,15 @@ var (
ErrPairingCancelled = errors.New("user cancelled pairing on phone") ErrPairingCancelled = errors.New("user cancelled pairing on phone")
ErrPairingTimeout = errors.New("pairing timed out") ErrPairingTimeout = errors.New("pairing timed out")
ErrPairingInitTimeout = errors.New("client init timed out") ErrPairingInitTimeout = errors.New("client init timed out")
ErrHadMultipleDevices = errors.New("had multiple primary-looking devices")
) )
const GaiaInitTimeout = 15 * time.Second const GaiaInitTimeout = 20 * time.Second
type primaryDeviceID struct {
regID string
unknownInt uint64
}
func (c *Client) DoGaiaPairing(ctx context.Context, emojiCallback func(string)) error { func (c *Client) DoGaiaPairing(ctx context.Context, emojiCallback func(string)) error {
if len(c.AuthData.Cookies) == 0 { if len(c.AuthData.Cookies) == 0 {
@ -262,24 +268,25 @@ func (c *Client) DoGaiaPairing(ctx context.Context, emojiCallback func(string))
Str("maybe_browser_uuid", sigResp.MaybeBrowserUUID). Str("maybe_browser_uuid", sigResp.MaybeBrowserUUID).
Any("device_data", sigResp.DeviceData). Any("device_data", sigResp.DeviceData).
Msg("Gaia devices response") Msg("Gaia devices response")
// TODO multiple devices? var primaryDevices []primaryDeviceID
var destRegID string
var destRegUnknownInt uint64
for _, dev := range sigResp.GetDeviceData().GetUnknownItems2() { for _, dev := range sigResp.GetDeviceData().GetUnknownItems2() {
if dev.GetUnknownInt4() == 1 { if dev.GetUnknownInt4() == 1 {
if destRegID != "" { primaryDevices = append(primaryDevices, primaryDeviceID{
regID: dev.GetDestOrSourceUUID(),
unknownInt: dev.GetUnknownBigInt7(),
})
}
}
if len(primaryDevices) == 0 {
return ErrNoDevicesFound
} else if len(primaryDevices) > 1 {
zerolog.Ctx(ctx).Warn(). zerolog.Ctx(ctx).Warn().
Str("prev_reg_id", destRegID). Any("devices", primaryDevices).
Str("next_reg_id", dev.GetDestOrSourceUUID()). Int("hacky_device_switcher", c.GaiaHackyDeviceSwitcher).
Msg("Found multiple primary-looking devices for gaia pairing") Msg("Found multiple primary-looking devices for gaia pairing")
} }
destRegID = dev.GetDestOrSourceUUID() destRegID := primaryDevices[c.GaiaHackyDeviceSwitcher%len(primaryDevices)].regID
destRegUnknownInt = dev.GetUnknownBigInt7() destRegUnknownInt := primaryDevices[c.GaiaHackyDeviceSwitcher%len(primaryDevices)].unknownInt
}
}
if destRegID == "" {
return ErrNoDevicesFound
}
zerolog.Ctx(ctx).Debug(). zerolog.Ctx(ctx).Debug().
Str("dest_reg_uuid", destRegID). Str("dest_reg_uuid", destRegID).
Uint64("dest_reg_unknown_int", destRegUnknownInt). Uint64("dest_reg_unknown_int", destRegUnknownInt).
@ -307,7 +314,11 @@ func (c *Client) DoGaiaPairing(ctx context.Context, emojiCallback func(string))
zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to send gaia pairing cancel request after init timeout") zerolog.Ctx(ctx).Warn().Err(err).Msg("Failed to send gaia pairing cancel request after init timeout")
} }
if errors.Is(err, context.DeadlineExceeded) { if errors.Is(err, context.DeadlineExceeded) {
return ErrPairingInitTimeout err = ErrPairingInitTimeout
if len(primaryDevices) > 1 {
err = fmt.Errorf("%w (%w)", ErrPairingInitTimeout, ErrHadMultipleDevices)
}
return err
} }
return fmt.Errorf("failed to send client init: %w", err) return fmt.Errorf("failed to send client init: %w", err)
} }

View file

@ -79,6 +79,7 @@ type User struct {
didHackySetActive bool didHackySetActive bool
noDataReceivedRecently bool noDataReceivedRecently bool
lastDataReceived time.Time lastDataReceived time.Time
gaiaHackyDeviceSwitcher int
loginInProgress atomic.Bool loginInProgress atomic.Bool
pairSuccessChan chan struct{} pairSuccessChan chan struct{}
@ -557,6 +558,7 @@ func (user *User) LoginGoogle(ctx context.Context, cookies map[string]string, em
authData.Cookies = cookies authData.Cookies = cookies
user.createClient(authData) user.createClient(authData)
Analytics.Track(user.MXID, "$login_start", map[string]any{"mode": "google"}) Analytics.Track(user.MXID, "$login_start", map[string]any{"mode": "google"})
user.Client.GaiaHackyDeviceSwitcher = user.gaiaHackyDeviceSwitcher
err := user.Client.DoGaiaPairing(ctx, emojiCallback) err := user.Client.DoGaiaPairing(ctx, emojiCallback)
if err != nil { if err != nil {
user.unlockedDeleteConnection() user.unlockedDeleteConnection()
@ -570,7 +572,12 @@ func (user *User) LoginGoogle(ctx context.Context, cookies map[string]string, em
case errors.Is(err, libgm.ErrPairingTimeout): case errors.Is(err, libgm.ErrPairingTimeout):
Analytics.Track(user.MXID, "$login_failure", map[string]any{"mode": "google", "error": "user timeout"}) Analytics.Track(user.MXID, "$login_failure", map[string]any{"mode": "google", "error": "user timeout"})
case errors.Is(err, libgm.ErrPairingInitTimeout): case errors.Is(err, libgm.ErrPairingInitTimeout):
if errors.Is(err, libgm.ErrHadMultipleDevices) {
user.gaiaHackyDeviceSwitcher++
Analytics.Track(user.MXID, "$login_failure", map[string]any{"mode": "google", "error": "init timeout (multiple devices)"})
} else {
Analytics.Track(user.MXID, "$login_failure", map[string]any{"mode": "google", "error": "init timeout"}) Analytics.Track(user.MXID, "$login_failure", map[string]any{"mode": "google", "error": "init timeout"})
}
default: default:
Analytics.Track(user.MXID, "$login_failure", map[string]any{"mode": "google", "error": "unknown"}) Analytics.Track(user.MXID, "$login_failure", map[string]any{"mode": "google", "error": "unknown"})
} }