Prompt user for sudo password and validate.
Runs sudo -v to cache credentials for subsequent commands.
Retries up to three times before exiting the program.
Exits program if authentication fails.
Source code in src/battery_boost/authenticate.py
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 | def authenticate(_parent: App) -> None:
"""Prompt user for sudo password and validate.
Runs `sudo -v` to cache credentials for subsequent commands.
Retries up to three times before exiting the program.
Exits program if authentication fails.
"""
max_tries = 3
for attempt in range(max_tries):
_password = simpledialog.askstring(
"Authenticate",
"Authentication Required to run Battery Boost.\n\nEnter your password:",
show="*"
)
if _password is None:
_parent.quit_app("Cancelled.")
# Don't strip() - whitespaces are unusual but valid password characters.
if not _password:
if attempt < max_tries - 1:
messagebox.showerror("Error", "Password required.")
continue
break
try:
subprocess.run(['sudo', '-S', '-v'],
input=_password + '\n',
text=True,
capture_output=True,
timeout=20, # Unlikely, but better than hanging.
check=True)
_password = None # Overwrite password immediately.
return
except FileNotFoundError:
_parent.quit_on_error("sudo not found on this system.")
except subprocess.TimeoutExpired:
_parent.quit_on_error("Authentication process timed out.",
"Fatal Error")
except subprocess.CalledProcessError:
# Only realistic failure remaining is "wrong password".
if attempt < max_tries - 1:
messagebox.showerror("Error", "Incorrect password.")
except Exception as exc: # pylint: disable=broad-exception-caught
# Defensively catch any unexpected errors and quit.
_parent.quit_on_error(f"Unexpected Error {exc}",
"Fatal Error")
finally:
_password = None # Ensure always cleared.
# Failed every attempt.
message = f"Authentication failed {max_tries} times.\n\nClick OK to Quit."
_parent.quit_on_error(message)
|