-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcommand.py
executable file
·124 lines (102 loc) · 3.98 KB
/
command.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
#!/usr/bin/python3
"""
Name: cuddlyclara
Website: cuddlyclara.de
Source: https://github.com/cuddlyclara/SSHKeyFetch
Description: This program uses SSH keys stored in GitHub for secure client authentication with OpenSSH servers via the "AuthorizedKeysCommand" option.
"""
import requests
import sys
import os
import yaml
import time
from timeout_decorator import timeout
# Set Timeout
@timeout(10)
def get_github_keys(username, token=None):
# Build the GitHub API URL for fetching user keys
url = f'https://api.github.com/users/{username}/keys'
# Define the base headers
headers = {
'Accept': 'application/vnd.github.v3+json'
}
# Add an optional token to the headers if provided
if token is not None:
headers['Authorization'] = f'token {token}'
# Send a GET request to fetch user keys
response = requests.get(url, headers=headers, timeout=5)
# Check if the response status code is not 200 (OK)
if response.status_code != 200:
raise ValueError('Bad return code')
# Extract and return the user keys
return [key['key'] for key in response.json()]
def write_cachefile(keys, path):
# Write keys to the cache file
with open(path, 'w') as cachefile:
for key in keys:
cachefile.write(key + '\n')
def read_cachefile(path):
# Read keys from the cache file
with open(path, 'r') as cachefile:
keys = [key.strip() for key in cachefile.readlines()]
return keys
def check_cachefile_changed_recently(path, threshold_seconds=10):
if os.path.exists(path):
file_modified_time = os.path.getmtime(path)
current_time = time.time()
return current_time - file_modified_time <= threshold_seconds
return False
def write_console(keys):
# Print the keys to the console via stdout
for key in keys:
print(key)
def get_configuration(username):
# Get the path to the user's configuration file
config_file_path = os.path.expanduser(f'~{username}/.ssh/github.yaml')
# Read the configuration from YAML file
with open(config_file_path, 'r') as configuration_file:
config = yaml.safe_load(configuration_file)
# Check if 'username' is present in the configuration file
if 'username' not in config:
raise ValueError('Username not set in config file')
return config
def main(username):
# Path for the cache file
cachefilepath = os.path.expanduser(f'~{username}/.ssh/authorized_keys_github')
# Try to load the configuration file
try:
config = get_configuration(username)
except Exception as e:
# If configuration is not readable, print the error message to stderr and exit with code 1
print(e, file=sys.stderr)
exit(1)
try:
if check_cachefile_changed_recently(cachefilepath):
# If the cache file has been recently updated, retrieve keys from it to reduce the number of requests to GitHub
keys = read_cachefile(cachefilepath)
else:
try:
# Otherwise, obtain keys from GitHub and store them in the cache
keys = get_github_keys(config.get('username'), config.get('token'))
write_cachefile(keys, cachefilepath)
except Exception as e:
# If there's an exception while accessing GitHub, print the error message and try to read keys from the cache file
print(e, file=sys.stderr)
keys = read_cachefile(cachefilepath)
except Exception as e:
# If cachefile is not readable, print the error message and use an empty key list
print(e, file=sys.stderr)
keys = []
write_console(keys)
if __name__ == '__main__':
# Verify if the username has been specified as a command-line argument
if len(sys.argv) != 2:
sys.exit(1)
# Get the username from the command-line argument
username = sys.argv[1]
# Call the main function
try:
main(username)
except Exception as e:
print(e, file=sys.stderr)
exit(1)