-
Notifications
You must be signed in to change notification settings - Fork 9
/
main.py
143 lines (128 loc) · 5.09 KB
/
main.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
137
138
139
140
141
142
143
import subprocess
import decky_plugin
import os
import re
import logging
os.environ["XDG_RUNTIME_DIR"] = "/run/user/1000"
# Setup environment variables
deckyHomeDir = decky_plugin.DECKY_HOME
settingsDir = decky_plugin.DECKY_PLUGIN_SETTINGS_DIR
loggingDir = decky_plugin.DECKY_PLUGIN_LOG_DIR
logger = decky_plugin.logger
# Add install directories used by https://github.com/tailscale-dev/deck-tailscale
# and Nix (https://github.com/saumya-banthia/tailscale-control/issues/7) to the PATH
user_dirs = ["/opt/tailscale", "/home/deck/.nix-profile/bin"]
current_path = os.environ["PATH"].split(":")
new_path = ":".join(
current_path + [user_dir for user_dir in user_dirs if user_dir not in current_path]
)
os.environ["PATH"] = new_path
# Setup backend logger
logger.setLevel(logging.DEBUG) # can be changed to logging.DEBUG for debugging issues
logger.info("[backend] Settings path: {}".format(settingsDir))
class Plugin:
async def up(
self,
node_ip="",
allow_lan_access=True,
custom_flags="",
login_server="",
):
"""
Bring up the Tailscale connection.
Args:
node_ip (str): The IP address of the exit node.
allow_lan_access (bool): Whether to allow LAN access.
login_server (str): Tailscale login server url
custom_flags (str): User defined flags
Returns:
bool: True if the Tailscale connection is successfully brought up, False otherwise.
"""
try:
allow_lan_access = bool(allow_lan_access)
node_ip = str(node_ip).split()[0] if node_ip else ""
cmd_list = ["tailscale", "up", f"--exit-node={node_ip}"]
cmd_list.append("--exit-node-allow-lan-access=true") if node_ip != "" and allow_lan_access else None
[cmd_list.append(elem) for elem in custom_flags.split()] if custom_flags != "" else None
cmd_list.append(f"--login-server={login_server}") if login_server else None
cmd_list.append("--reset")
logger.debug(f"Tailscale up with command: {' '.join(cmd_list)}")
return not subprocess.run(cmd_list, timeout=10, check=False)
except Exception as e:
logger.error(e, "error")
async def down(self):
"""
Bring down the Tailscale connection.
Returns:
bool: True if the Tailscale connection is successfully brought down, False otherwise.
"""
try:
subprocess.run(["tailscale", "down"], timeout=10, check=False)
return True
except Exception as e:
logger.error(e, "error")
async def get_tailscale_state(self):
"""
Get the state of the Tailscale connection.
Returns:
bool: True if the Tailscale connection is active, False otherwise.
"""
try:
result = not subprocess.call(
["tailscale", "status"], timeout=10, stdout=subprocess.DEVNULL
)
return result
except Exception as e:
logger.error(e, "error")
async def get_tailscale_exit_node_ip_list(self):
"""
Get the exit node of the Tailscale connection.
Returns:
str: The IP address of the exit node.
"""
try:
output = subprocess.check_output(
["tailscale", "status"], timeout=10, text=True
)
lines = [elem for elem in output.splitlines() if len(elem) != 0]
ip_pattern = r"\b(?:\d{1,3}\.){3}\d{1,3}\b"
# over-engineered regex to avoid matching "exit node" in the middle of a line
node_pattern = ip_pattern + r".*(-|offline|online|active|idle).*exit node"
return [
f"{re.findall(ip_pattern, line)[0]} ({line.split()[1]})"
for line in lines
if re.search(node_pattern, line)
]
except Exception as e:
logger.error(e, "error")
async def get_tailscale_device_status(self):
"""
Get the status of Tailscale devices.
Returns:
dict: A dictionary containing the name and status of Tailscale devices.
"""
try:
output = subprocess.check_output(
["tailscale", "status"], timeout=10, text=True
)
lines = [elem for elem in output.splitlines() if len(elem) != 0]
output_dict = {
# "ip": [],
"name": [],
# "type": [],
"status": [],
}
for line in lines:
parts = line.split()
# check if first part is an ip address
if not parts[0].count(".") == 3:
continue
# output_dict["ip"].append(parts[0])
output_dict["name"].append(parts[1])
# output_dict["type"].append(parts[3])
output_dict["status"].append(parts[4].replace(";", ""))
logger.debug(output)
logger.debug(output_dict)
return output_dict
except Exception as e:
logger.error(e, "error")