forked from TimidRobot/gacli
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathga
More file actions
executable file
·145 lines (122 loc) · 3.99 KB
/
ga
File metadata and controls
executable file
·145 lines (122 loc) · 3.99 KB
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
137
138
139
140
141
142
143
144
145
#!/usr/bin/env python
"""Copy newline terminated TOTP verification code to the clipboard."""
# Standard library
from __future__ import absolute_import, division, print_function
from distutils.spawn import find_executable
import argparse
import os.path
import platform
import stat
import subprocess
import sys
import time
# Third-party
import onetimepass as otp
EPILOG = """The debug option continually prints verification codes instead of
copying a single code to the clipboard."""
def send_data_to_cmd(cmd, data):
"""Send data to specified command.
"""
p = subprocess.Popen([cmd], stdin=subprocess.PIPE, universal_newlines=True)
p.stdin.write(data)
p.stdin.close()
exit_status = p.wait()
return exit_status
def find_copy_to_clip_cmd():
"""Attempt to find command to copy to clipboard or default to cat.
"""
if platform.system() == "Darwin":
return "pbcopy"
elif platform.system() == "Linux":
if find_executable("xclip"):
return "xclip"
elif find_executable("xsel"):
return "xseli -i"
return "cat"
def continuously_display_codes(secret):
"""Display new code every minute and half-minute.
"""
code = ""
print("{:<10}{}".format("Time", "Verification Code"))
print("{:<10}{}".format("====", "================="))
while True:
if not code or time.strftime("%S") in ("00", "30"):
code = get_code(secret)
print("{:<10}{}".format(time.strftime("%H:%M:%S"), code))
time.sleep(1)
def get_code(secret):
"""Get TOTP verification code.
"""
try:
code = otp.get_totp(secret, True)
except Exception as e:
name = e.__class__.__name__
print("ERROR: {}:".format(name), end=None)
for arg in e.args:
print(arg, end=None)
print()
sys.exit(1)
code = code.decode(sys.stdout.encoding)
return code
def validate_secret_path(path):
"""Validate secret file exists and has secure permissions."""
path = os.path.expanduser(path)
if os.path.exists(path):
path = os.path.abspath(path)
else:
print("ERROR: file does not exist: {}".format(path))
sys.exit(1)
# validate file permissions
required_mode = "0400"
secret_stat = os.stat(path)
secret_mode = oct(stat.S_IMODE(secret_stat.st_mode))
if secret_mode != required_mode:
print("ERROR: permissions of secret file must be {} instead of {}"
.format(required_mode, secret_mode))
sys.exit(1)
return path
def read_secret(args):
"""Read secret from file.
"""
if args.file == "-":
secret_file = sys.stdin
else:
# validate secret file path
secret_path = validate_secret_path(args.file)
if args.debug:
print("Secret file path: {}".format(secret_path), end="\n\n")
# read secret from file
secret_file = open(secret_path, "r")
for line in secret_file.readlines():
line = line.strip()
# ignore comments and blank line
if len(line) == 0 or line[0] in ("\"", "#"):
continue
# return 1st possible line
secret_file.close()
return line
def parser_setup():
"""Instantiate, configure and return an argparse instance.
"""
ap = argparse.ArgumentParser(description=__doc__, epilog=EPILOG)
ap.add_argument("-d", "--debug", action="store_true",
help="print debug information")
ap.add_argument("-f", "--file", type=str, default="~/.ga",
help="Secret file (use \"-\" for stdin)")
return ap.parse_args()
def main():
args = parser_setup()
secret = read_secret(args)
if args.debug:
continuously_display_codes(secret)
else:
code = "{}\n".format(get_code(secret))
cmd = find_copy_to_clip_cmd()
exit_status = send_data_to_cmd(cmd, code)
sys.exit(exit_status)
if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
print()
sys.exit(130)