Fix auth: keep Sign In button locked, pipe code into waiting auth process 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:32:23 -04:00
1 parent 9e6cdeb9c3
commit 02c3e9639e
1 file changed
+58 -19
+58 -19
View File
@@ -1188,32 +1188,59 @@ class AuthPage(Gtk.Box):
def _on_auth(self, btn):
btn.set_sensitive(False)
btn.set_label("Signing in…")
args = ["auth"]
btn.set_label("Waiting for Apple…")
self._auth_btn = btn
cmd = [ICLOUDCTL, "auth"]
if self.sms_check.get_active():
args.append("--force-sms")
cmd.append("--force-sms")
if self.debug_check.get_active():
args.append("--debug")
self.status_label.set_markup('<span fgcolor="#64a6e0">Connecting to Apple — a code will be sent to your device…</span>')
cmd.append("--debug")
self.status_label.set_markup('<span fgcolor="#64a6e0">Connecting to Apple — a code will appear on your device…</span>')
def _worker():
rc, out, err = icloudctl(*args)
GLib.idle_add(self._auth_result, rc, out + err, btn)
threading.Thread(target=_worker, daemon=True).start()
def _auth_result(self, rc, output, btn):
try:
self._auth_proc = subprocess.Popen(
cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, text=True, bufsize=1
)
except Exception as e:
btn.set_sensitive(True)
btn.set_label("Sign in with Apple ID")
if "two-factor" in output.lower() or "verification" in output.lower() or "2fa" in output.lower() or "enter" in output.lower():
self.status_label.set_markup(
'<span fgcolor="#e6a020">Code sent — enter it in the box below.</span>'
)
self.status_label.set_markup(f'<span fgcolor="#c6262e">Failed to start: {e}</span>')
return
proc = self._auth_proc
output_lines = []
def _reader():
for line in proc.stdout:
output_lines.append(line)
low = line.lower()
if "code" in low or "enter" in low or "sent" in low or "2fa" in low:
GLib.idle_add(self._prompt_for_code)
proc.wait()
out = "".join(output_lines)
GLib.idle_add(self._auth_proc_done, proc.returncode, out)
threading.Thread(target=_reader, daemon=True).start()
def _prompt_for_code(self):
self.status_label.set_markup('<span fgcolor="#e6a020">Code sent — enter it below and click Verify.</span>')
self.tfa_entry.grab_focus()
elif rc == 0:
def _auth_proc_done(self, rc, output):
if rc == 0 and "authenticated" in output.lower():
self._unlock_auth_btn()
self.status_label.set_markup('<span fgcolor="#68b723">Authentication successful!</span>')
else:
msg = GLib.markup_escape_text(output[:300])
self.status_label.set_markup(f'<span fgcolor="#c6262e">{msg}</span>')
elif rc != 0:
self._unlock_auth_btn()
msg = GLib.markup_escape_text(output[-300:].strip())
self.status_label.set_markup(f'<span fgcolor="#c6262e">{msg or f"Exited {rc}"}</span>')
# rc==0 but still waiting for code → leave button locked until _on_tfa completes
def _unlock_auth_btn(self):
if hasattr(self, "_auth_btn"):
self._auth_btn.set_sensitive(True)
self._auth_btn.set_label("Sign in with Apple ID")
def _on_tfa(self, _):
code = self.tfa_entry.get_text().strip()
@@ -1222,12 +1249,24 @@ class AuthPage(Gtk.Box):
return
self.tfa_status.set_markup('<span fgcolor="#64a6e0">Verifying…</span>')
proc = getattr(self, "_auth_proc", None)
if proc and proc.poll() is None:
# Feed the code into the waiting auth process
try:
proc.stdin.write(code + "\n")
proc.stdin.flush()
except Exception as e:
self.tfa_status.set_markup(f'<span fgcolor="#c6262e">Error: {e}</span>')
return
# auth process already finished — run a fresh auth with code piped in
def _worker():
rc, out, err = icloudctl("auth", input_data=code + "\n")
GLib.idle_add(self._tfa_result, rc, out + err)
threading.Thread(target=_worker, daemon=True).start()
def _tfa_result(self, rc, output):
self._unlock_auth_btn()
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("")