From 02dc41d63fb41797a5653f4fbe264eeb2d7b3714 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 22 Dec 2025 08:37:45 +0000 Subject: [PATCH] Refactor letsencrypt script to use /dev/tty for interactive prompts Co-authored-by: mathieumoran1 --- .../__pycache__/letsencrypt.cpython-312.pyc | Bin 13403 -> 14502 bytes python_video_server/letsencrypt.py | 78 ++++++++++++++---- 2 files changed, 61 insertions(+), 17 deletions(-) diff --git a/python_video_server/__pycache__/letsencrypt.cpython-312.pyc b/python_video_server/__pycache__/letsencrypt.cpython-312.pyc index db3748896b5552326550706679529c0304775b6b..7d125dbac28e073c70a0cb4a46c0503154bc900a 100644 GIT binary patch delta 1563 zcmchW%TE(Q7{J|vqJ&Z!(4aB+Wf9YcS1W1^T9kko5~wjY>VbqzcW3E@?M$7WO2mb(kTs-N_Zc7(XVq)SP_VK;v`+ncY(#w18@8a>+ z1M=jXrpf2*oA&j1>`{xq5x?TivkIp3Lae6JqpcuMFHB%AicCNmt%89n!sQqoVKP?? z%NOPxm<1)q7M)8lY~rP1=?xa+26n)8FdtkZ4k_9grf<|DE|)L`M1fF&IWh!U!XUrO zgnGyZyh0q|3eO1T1evHzugs-x^IKn_wt994{;OPp?- zqk2QY5~u8_z|sNosEkJe);Km8H|MGReGs*gCWY0CGAZ0GL>0>UHnLr*T3bRkF_Dl3 z@9_11CT6{;k3I%rIqBB0d2$Xph)gt)5)0IThyzp(HP0w+v_UF{mN^kPC9fOyOx;z9 zgLb4MvS2bjN?kk3ieqHjgyNc^|0;RLQ|d-weU6S785h_blC?MD)vb2tQS#d0vm=@9 zZd-&R+m65y_(y3`0(Cr<+pw8aFDev+89%isV$Nt}BquoG$Tg0GRflcg!6h z$z=3&qhX z-wp@6Eb;R<knaXNY1YnHz0>PQw42rLp+uARxSGnoj?PZseQ6%e0hb@(N!2$&W>SCtLIHoy;QO##T_2nOCAQ zIZ8lX_LDIaxU~%#_5E%=|o5?Mg9uj%g*SMG7SusR~7tl?CmCfM$T*rL5qYrcj=$ zUX-eknWvDbke8pQ3v_#GQDSmQW?8C2YF=4pQGQ--YF>$sLV03l2~bTEh|Eg?nU<%J zoS#>cnOB;sH#to>M$F7WNfY8>Bu^_%zAfxNSx>}F8f;}rQKc1_0aB8gS5R7_p=75p zxkki?Nt0`GypZ_hw<69=ri{Q)Ri1oLG}JmJKQ}Qm51|JVmOxLr_yy}47%C*^q$cK- z7Fa>U1;yq(G2_WL0-Te(#Xm9jOs=2{gW7Dmp^r!;18GOBJ)HsWVyjM`jmx|WIEg^^MDvmeuBb&Glc D-yWQ6 diff --git a/python_video_server/letsencrypt.py b/python_video_server/letsencrypt.py index 4ed280e..0277f4f 100644 --- a/python_video_server/letsencrypt.py +++ b/python_video_server/letsencrypt.py @@ -89,32 +89,60 @@ import os import sys import time +def _open_tty(): + # Certbot may capture stdout/stderr of hooks; /dev/tty forces user-visible IO + # when an interactive terminal exists. + try: + return open("/dev/tty", "r+", encoding="utf-8", buffering=1) + except Exception: + return None + def main() -> int: domain = os.environ.get("CERTBOT_DOMAIN", "").strip() validation = os.environ.get("CERTBOT_VALIDATION", "").strip() if not domain or not validation: - print("Missing CERTBOT_DOMAIN/CERTBOT_VALIDATION in environment.", file=sys.stderr) + print("Missing CERTBOT_DOMAIN/CERTBOT_VALIDATION in environment.", file=sys.stderr, flush=True) return 2 record_name = f"_acme-challenge.{domain}" - print("\\n=== DNS-01 challenge required ===") - print(f"Create/Update this TXT record:") - print(f" Name: {record_name}") - print(f" Type: TXT") - print(f" Value: {validation}") - print("\\nAfter the record is published and has propagated, press Enter to continue.") + msg = ( + "\\n=== DNS-01 challenge required ===\\n" + "Create/Update this TXT record:\\n" + f" Name: {record_name}\\n" + " Type: TXT\\n" + f" Value: {validation}\\n" + "\\nAfter the record is published and has propagated, press Enter to continue.\\n" + "> " + ) - # If we're in a non-interactive environment, wait a bit and then continue. - if not sys.stdin.isatty(): - wait_s = int(os.environ.get("LE_DNS_WAIT_SECONDS", "60")) - print(f"(non-interactive stdin detected; waiting {wait_s}s then continuing...)") - time.sleep(max(0, wait_s)) + tty = _open_tty() + if tty is not None: + tty.write(msg) + tty.flush() + try: + tty.readline() + except KeyboardInterrupt: + tty.write("\\nAborted.\\n") + tty.flush() + return 130 + finally: + try: + tty.close() + except Exception: + pass return 0 + # Fallback: best-effort stdout + either wait or read stdin if interactive. + print(msg, end="", flush=True) + if not sys.stdin.isatty(): + wait_s = int(os.environ.get("LE_DNS_WAIT_SECONDS", "300")) + print(f"\\n(non-interactive stdin detected; waiting {wait_s}s then continuing...)", flush=True) + time.sleep(max(0, wait_s)) + return 0 try: - input("> ") + input("") except KeyboardInterrupt: - print("\\nAborted.", file=sys.stderr) + print("\\nAborted.", file=sys.stderr, flush=True) return 130 return 0 @@ -125,11 +153,27 @@ if __name__ == "__main__": cleanup_contents = """#!/usr/bin/env python3 import os +def _open_tty(): + try: + return open("/dev/tty", "w", encoding="utf-8", buffering=1) + except Exception: + return None + def main() -> int: domain = os.environ.get("CERTBOT_DOMAIN", "").strip() - if domain: - print("\\nDNS-01 cleanup:") - print(f"You may now remove the TXT record: _acme-challenge.{domain}") + if not domain: + return 0 + msg = "\\nDNS-01 cleanup:\\nYou may now remove the TXT record: _acme-challenge.%s\\n" % domain + tty = _open_tty() + if tty is not None: + tty.write(msg) + tty.flush() + try: + tty.close() + except Exception: + pass + return 0 + print(msg, end="", flush=True) return 0 if __name__ == "__main__":