Handle 2FA device selector dialog on multi-method accounts (refs #20) - #21
Conversation
…e-hustler-ft3d#7, refs code-hustler-ft3d#20) The Second Factor Authentication dialog on a multi-method account is a device selector (JTextArea heading 'Select second factor device' + a JList of devices + OK/Cancel/Help), not a code-entry form. The controller previously typed the TOTP into the heading JTextArea via SETTEXT_IN_WIN's catch-all fallback and clicked OK — appearing to succeed while submitting nothing, then failing with 'Re-login is required'. Changes: - agent: add JLIST_SELECT command (protocol v0.2 -> v0.3) to select an item by text in the first JList of a window (mirrors IBC's SecondFactorDevice handling of the same dialog) - agent: SETTEXT_IN_WIN fallback now only considers JTextField / JPasswordField, never JTextArea headings — prevents silently typing into dialog headings - controller: detect the device selector, select TWOFA_DEVICE, click OK, poll for the code-entry dialog; fail with ALERT_2FA_FAILED if the switch is rejected instead of mis-typing - controller: broaden SETTEXT/CLICK title candidates since the code-entry dialog title may differ from the selector's Caveat: on Gateway 10.45.1c the server rejects the mid-login device switch (Re-login is required, 3/3 reproducible; device choice does not persist). The PR still delivers accurate failure detection and the fallback bugfix; the switch itself may work on older Gateway versions. See issue code-hustler-ft3d#20 for full findings and test plan.
|
Thanks — this is a solid find, and the dump in #20 settles something left open since the v0.7.0 spike: the multi-method dialog shape is account-dependent. The account v0.7.0 was validated against gets a pre-defaulted code dialog with a hidden "Change input method" link (no JList anywhere in its tree); yours gets the IBC-style selector. Both are real on 10.45.x. I reproduced your findings against a mock dialog built from your component-tree dump, driven by the real agent jar and the real
I've pushed your commit untouched to
Could you run that branch against your multi-method account? Expected: within ~20s of the selector appearing you get the new That rejected-switch path on a real account is the one thing that can't be exercised here — everything else (selector detection, list drive, link-variant no-regression, and the switch-accepted flow against a mock that swaps in the code panel) is covered. If your run behaves, I'll merge the PR with the follow-ups and cut a release. |
|
Merged to This ships in the next tagged release together with a docs pass (README/UPGRADING still describe only the code-dialog variant). No action needed on your side — though if you do get a chance to run Thanks for an excellent contribution — the component-tree dump in #20 was the ground truth this had been missing since May, and the |
The unittest invocation was piped through tail -5, so make test's exit status was tail's and a failing suite still exited 0 — CI has never been able to catch a unit-test regression. Drop the pipe (and -v; non-verbose discover output is compact) and propagate failure. Verified in both directions. Add TestHandle2faSelectorFlow: switch-rejected emits the dedicated ALERT reason and never types the code; switch-accepted completes the selector -> code-entry -> TOTP flow; JLIST_SELECT failure fails loud; a link-variant dump never touches the selector path. Mirrors the mock-dialog harness scenarios that validated #21.
Closes #7 (partial): multi-method 2FA dialog is a device selector and is now detected + driven mechanically; the switch is rejected server-side on 10.45.1c (see #20), so on current versions the net effect is accurate failure detection and a SETTEXT fallback bugfix.
Changes
agent/GatewayInputAgent.java
JLIST_SELECT <title>|<item>command (protocol v0.2 → v0.3): select an item by text in the first JList of a window.SETTEXT_IN_WINfallback: only consider JTextField/JPasswordField, never JTextArea headings — the old catch-all fallback typed the TOTP into theSelect second factor deviceheading (silently, returning OK).gateway_controller.py
agent_jlist_select()helper.handle_2faTOTP branch: detect the device selector via component-tree dump (the heading is a JTextArea, invisible toagent_labels()), selectTWOFA_DEVICE, click OK, poll up to 15s for the code-entry dialog. If the switch is rejected → clearALERT_2FA_FAILED(previously:2FA handled successfullythen a failed login).Test plan (hand-written, per CONTRIBUTING)
make clean && makepasses (JDK 17). ✅ verified locally.Full findings, component-tree dump and screenshot description in issue #20.