-
-
Notifications
You must be signed in to change notification settings - Fork 148
/
cli.py
executable file
·136 lines (112 loc) · 3.84 KB
/
cli.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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/env python
"""Simple command line interface to get/set password from a keyring"""
import getpass
import argparse
import sys
from . import core
from . import backend
from . import set_keyring, get_password, set_password, delete_password
class CommandLineTool:
def __init__(self):
self.parser = argparse.ArgumentParser()
self.parser.add_argument(
"-p",
"--keyring-path",
dest="keyring_path",
default=None,
help="Path to the keyring backend",
)
self.parser.add_argument(
"-b",
"--keyring-backend",
dest="keyring_backend",
default=None,
help="Name of the keyring backend",
)
self.parser.add_argument(
"--list-backends",
action="store_true",
help="List keyring backends and exit",
)
self.parser.add_argument(
"--disable", action="store_true", help="Disable keyring and exit"
)
self.parser.add_argument(
'operation',
choices=["get", "set", "del"],
nargs="?",
)
self.parser.add_argument(
'service',
nargs="?",
)
self.parser.add_argument(
'username',
nargs="?",
)
def run(self, argv):
args = self.parser.parse_args(argv)
vars(self).update(vars(args))
if args.list_backends:
for k in backend.get_all_keyring():
print(k)
return
if args.disable:
core.disable()
return
self._check_args()
self._load_spec_backend()
method = getattr(self, f'do_{self.operation}', self.invalid_op)
return method()
def _check_args(self):
if self.operation:
if self.service is None or self.username is None:
self.parser.error(f"{self.operation} requires service and username")
def do_get(self):
password = get_password(self.service, self.username)
if password is None:
raise SystemExit(1)
print(password)
def do_set(self):
password = self.input_password(
f"Password for '{self.username}' in '{self.service}': "
)
set_password(self.service, self.username, password)
def do_del(self):
delete_password(self.service, self.username)
def invalid_op(self):
self.parser.error("Specify operation 'get', 'del', or 'set'.")
def _load_spec_backend(self):
if self.keyring_backend is None:
return
try:
if self.keyring_path:
sys.path.insert(0, self.keyring_path)
set_keyring(core.load_keyring(self.keyring_backend))
except (Exception,) as exc:
# Tons of things can go wrong here:
# ImportError when using "fjkljfljkl"
# AttributeError when using "os.path.bar"
# TypeError when using "__builtins__.str"
# So, we play on the safe side, and catch everything.
self.parser.error(f"Unable to load specified keyring: {exc}")
def input_password(self, prompt):
"""Retrieve password from input."""
return self.pass_from_pipe() or getpass.getpass(prompt)
@classmethod
def pass_from_pipe(cls):
"""Return password from pipe if not on TTY, else False."""
is_pipe = not sys.stdin.isatty()
return is_pipe and cls.strip_last_newline(sys.stdin.read())
@staticmethod
def strip_last_newline(str):
"""Strip one last newline, if present."""
return str[: -str.endswith('\n')]
def main(argv=None):
"""Main command line interface."""
if argv is None:
argv = sys.argv[1:]
cli = CommandLineTool()
return cli.run(argv)
if __name__ == '__main__':
sys.exit(main())