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
+60 -21
+60 -21
View File
@@ -1188,32 +1188,59 @@ class AuthPage(Gtk.Box):
def _on_auth(self, btn): def _on_auth(self, btn):
btn.set_sensitive(False) btn.set_sensitive(False)
btn.set_label("Signing in…") btn.set_label("Waiting for Apple…")
args = ["auth"] self._auth_btn = btn
cmd = [ICLOUDCTL, "auth"]
if self.sms_check.get_active(): if self.sms_check.get_active():
args.append("--force-sms") cmd.append("--force-sms")
if self.debug_check.get_active(): if self.debug_check.get_active():
args.append("--debug") cmd.append("--debug")
self.status_label.set_markup('<span fgcolor="#64a6e0">Connecting to Apple — a code will be sent to your device…</span>') self.status_label.set_markup('<span fgcolor="#64a6e0">Connecting to Apple — a code will appear on your device…</span>')
def _worker(): try:
rc, out, err = icloudctl(*args) self._auth_proc = subprocess.Popen(
GLib.idle_add(self._auth_result, rc, out + err, btn) cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
threading.Thread(target=_worker, daemon=True).start() stderr=subprocess.STDOUT, text=True, bufsize=1
def _auth_result(self, rc, output, btn):
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.tfa_entry.grab_focus() except Exception as e:
elif rc == 0: btn.set_sensitive(True)
btn.set_label("Sign in with Apple ID")
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()
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>') self.status_label.set_markup('<span fgcolor="#68b723">Authentication successful!</span>')
else: elif rc != 0:
msg = GLib.markup_escape_text(output[:300]) self._unlock_auth_btn()
self.status_label.set_markup(f'<span fgcolor="#c6262e">{msg}</span>') 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, _): def _on_tfa(self, _):
code = self.tfa_entry.get_text().strip() code = self.tfa_entry.get_text().strip()
@@ -1222,12 +1249,24 @@ class AuthPage(Gtk.Box):
return return
self.tfa_status.set_markup('<span fgcolor="#64a6e0">Verifying…</span>') 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(): def _worker():
rc, out, err = icloudctl("auth", input_data=code + "\n") rc, out, err = icloudctl("auth", input_data=code + "\n")
GLib.idle_add(self._tfa_result, rc, out + err) GLib.idle_add(self._tfa_result, rc, out + err)
threading.Thread(target=_worker, daemon=True).start() threading.Thread(target=_worker, daemon=True).start()
def _tfa_result(self, rc, output): def _tfa_result(self, rc, output):
self._unlock_auth_btn()
if rc == 0 or "authenticated" in output.lower() or "success" in output.lower(): 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_status.set_markup('<span fgcolor="#68b723">Verified! You can now start the service.</span>')
self.tfa_entry.set_text("") self.tfa_entry.set_text("")