-
Notifications
You must be signed in to change notification settings - Fork 0
/
pinentry.py
53 lines (45 loc) · 1.64 KB
/
pinentry.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
import subprocess
class PinEntryException(Exception):
"""Error while getting pin entry."""
def get_pin(description="", prompt="", errormsg=""):
"""Run pinentry to get a password from the user.
Return value:
User password as a string. Could be empty.
None if the user pressed cancel.
Raises:
PinEntryException if something went wrong communicating with pinentry.
"""
try:
# Run pinentry, ignoring stderr.
pinentry = subprocess.Popen(["pinentry"],
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
except OSError:
# Could not launch pinentry.
raise PinEntryException("Could not launch pinentry")
commands = ""
commands += "SETDESC {}\n".format(description)
commands += "SETPROMPT {}\n".format(prompt)
commands += "SETERROR {}\n".format(errormsg)
commands += "OPTION grab\n"
commands += "GETPIN\n"
commands += "BYE\n"
output, _ = pinentry.communicate(input=commands)
output_lines = output.split("\n")
# Verify output.
if len(output_lines) < 8:
raise PinEntryException("Unexpected pinentry process output.")
xline = output_lines[-4]
yline = output_lines[-3]
if xline[:2] == "D ":
# User entered valid input.
return xline[2:].replace("%25", "%")
elif yline[:3] == "ERR":
# User cancelled.
return None
elif xline == "OK":
# User entered empty string.
return ""
else:
raise PinEntryException("Unexpected pinentry process output.")