-
Notifications
You must be signed in to change notification settings - Fork 0
/
pyoutline_tools.py
58 lines (51 loc) · 1.88 KB
/
pyoutline_tools.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
from socket import socket, gaierror
from base64 import urlsafe_b64decode
from binascii import Error as BAError
def get_free_port():
"""This func will return free port"""
with socket() as s:
s.bind(('', 0))
return s.getsockname()[1]
class OutlineKey:
def __init__(self, key: str):
self.key = key
try:
pass_enc_b64 = key.split('ss://')[1].split('@')[0]
for _ in range(3):
try:
pass_enc = urlsafe_b64decode(pass_enc_b64)
break
except BAError:
pass_enc_b64 += '='
else:
raise Exception
self.enc, self.password = pass_enc.decode().split(':')
server_port = key.split('@')[1].split('#')[0].split('/')[0].split(':')
self.server, self.port = server_port
except Exception as e:
raise ValueError(f'Invalid Key! {e}') from None
def __repr__(self) -> str:
return f'OutlineKey({self.key}) # at {id(self)}'
def __str__(self) -> str:
return (
f"""Key: {self.key}\nEnc: {self.enc}\nPassword: {self.password}\n"""
f"""Server: {self.server}\nPort: {self.port}"""
)
def shadowsocks(self, random_port: bool=False, port: int=None) -> str:
port = get_free_port() if random_port else (port if port else 53735)
return (
f"""ss-local -s "{self.server}" -p {self.port} -k """
f"""\"{self.password}" -m "{self.enc}" -l {port}"""
)
@property
def is_alive(self):
"""Will return True if addr:port is accessible"""
with socket() as s:
try:
s.bind((self.server, int(self.port)))
except gaierror:
return False
except OSError:
return True
except:
return False