Fix 2FA: always-visible code entry, Enter key submits, pipe code to icloudctl auth stdin

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Nate EmmertandClaude Sonnet 4.6 committed 2026-08-13 13:28:24 -04:00
1 parent 3aa5737c5e
commit ee39e39e02
1 file changed
+37 -24
+37 -24
View File
@@ -1150,27 +1150,41 @@ class AuthPage(Gtk.Box):
card.pack_start(self.status_label, False, False, 0)
self.pack_start(card, False, False, 0)
# 2FA section (hidden until needed)
self.tfa_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=8)
self.tfa_box.get_style_context().add_class("card")
self.tfa_box.set_no_show_all(True)
# 2FA section — always visible so user can enter code any time
tfa_card = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12)
tfa_card.get_style_context().add_class("card")
tfa_card.set_margin_top(4)
tfa_lbl = Gtk.Label()
tfa_lbl.set_markup("<b>Two-Factor Code</b>")
tfa_lbl.set_markup("<b>Two-Factor Authentication</b>")
tfa_lbl.set_halign(Gtk.Align.START)
tfa_sub = Gtk.Label(label="If Apple sent a code to your device, enter it here.")
tfa_sub.set_halign(Gtk.Align.START)
code_row = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=8)
self.tfa_entry = Gtk.Entry()
self.tfa_entry.set_placeholder_text("Enter 6-digit code from your device")
self.tfa_entry.set_placeholder_text("6-digit code")
self.tfa_entry.set_max_length(6)
self.tfa_entry.set_input_purpose(Gtk.InputPurpose.DIGITS)
self.tfa_entry.set_hexpand(True)
self.tfa_entry.connect("activate", self._on_tfa) # Enter key submits
btn_tfa = Gtk.Button(label="Verify Code")
btn_tfa.get_style_context().add_class("action-btn")
btn_tfa.get_style_context().add_class("btn-primary")
btn_tfa.connect("clicked", self._on_tfa)
self.tfa_box.pack_start(tfa_lbl, False, False, 0)
self.tfa_box.pack_start(self.tfa_entry, False, False, 0)
self.tfa_box.pack_start(btn_tfa, False, False, 0)
self.pack_start(self.tfa_box, False, False, 0)
code_row.pack_start(self.tfa_entry, True, True, 0)
code_row.pack_start(btn_tfa, False, False, 0)
self.tfa_status = Gtk.Label(label="")
self.tfa_status.set_halign(Gtk.Align.START)
tfa_card.pack_start(tfa_lbl, False, False, 0)
tfa_card.pack_start(tfa_sub, False, False, 0)
tfa_card.pack_start(code_row, False, False, 0)
tfa_card.pack_start(self.tfa_status, False, False, 0)
self.pack_start(tfa_card, False, False, 0)
def _on_auth(self, _):
args = ["auth"]
@@ -1186,21 +1200,23 @@ class AuthPage(Gtk.Box):
threading.Thread(target=_worker, daemon=True).start()
def _auth_result(self, rc, output):
if "two-factor" in output.lower() or "verification" in output.lower():
if "two-factor" in output.lower() or "verification" in output.lower() or "2fa" in output.lower():
self.status_label.set_markup(
'<span fgcolor="#e6a020">2FA required - enter code from your Apple device.</span>'
'<span fgcolor="#e6a020">A code was sent to your Apple device — enter it below.</span>'
)
self.tfa_box.show()
self.tfa_entry.grab_focus()
elif rc == 0:
self.status_label.set_markup('<span fgcolor="#68b723">Authentication successful!</span>')
else:
msg = GLib.markup_escape_text(output[:200])
self.status_label.set_markup(f'<span fgcolor="#c6262e">Error: {msg}</span>')
msg = GLib.markup_escape_text(output[:300])
self.status_label.set_markup(f'<span fgcolor="#c6262e">{msg}</span>')
def _on_tfa(self, _):
code = self.tfa_entry.get_text().strip()
if not code:
if len(code) < 6:
self.tfa_status.set_markup('<span fgcolor="#c6262e">Please enter the full 6-digit code.</span>')
return
self.tfa_status.set_markup('<span fgcolor="#64a6e0">Verifying…</span>')
def _worker():
rc, out, err = icloudctl("auth", input_data=code + "\n")
@@ -1208,15 +1224,12 @@ class AuthPage(Gtk.Box):
threading.Thread(target=_worker, daemon=True).start()
def _tfa_result(self, rc, output):
if rc == 0:
self.status_label.set_markup(
'<span fgcolor="#68b723">Verification complete! You can now start the service.</span>'
)
self.tfa_box.hide()
if rc == 0 or "authenticated" in output.lower() or "success" in output.lower():
self.tfa_status.set_markup('<span fgcolor="#68b723">Verified! You can now start the service.</span>')
self.tfa_entry.set_text("")
else:
self.status_label.set_markup(
'<span fgcolor="#c6262e">Verification failed. Try again.</span>'
)
msg = GLib.markup_escape_text(output[:200]) if output.strip() else f"exit code {rc}"
self.tfa_status.set_markup(f'<span fgcolor="#c6262e">Failed: {msg}</span>')
# ── Main window ────────────────────────────────────────────────────────────────