A simple cli for n3ro
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

97 lines
3.5KB

  1. import base64
  2. import csv
  3. import sys
  4. import os
  5. import urllib.request
  6. from urllib.parse import parse_qs
  7. class N3ROCLI:
  8. def __init__(self):
  9. self.config_path = os.path.expanduser('~/.config/n3ro-cli')
  10. self.ssr_command = f"python {self.config_path}/shadowsocksr/shadowsocks/local.py"
  11. self.url_path = os.path.join(self.config_path, 'url')
  12. self.cache_path = os.path.join(self.config_path, 'cache')
  13. self.subscribe_url = self.read_url()
  14. os.makedirs(self.config_path, exist_ok=True)
  15. def read_url(self):
  16. path_ok = os.path.exists(self.url_path)
  17. if path_ok:
  18. with open(self.url_path) as u:
  19. url = u.read()
  20. return url
  21. else:
  22. return None
  23. def decode_str(self, s, to_str=True):
  24. paddings = 4 - len(s) % 4
  25. padded_s = f"{s}{'='*paddings}"
  26. decoded = base64.urlsafe_b64decode(padded_s)
  27. if to_str:
  28. decoded = str(decoded, encoding='utf-8')
  29. return decoded
  30. def sync(self):
  31. if not self.subscribe_url:
  32. print("add a ssr subscribe url in ~/.config/n3ro-cli/url")
  33. else:
  34. with urllib.request.urlopen(self.subscribe_url) as resp:
  35. data = str(resp.read(), encoding='utf-8')
  36. ssr_urls = self.decode_str(data).strip().split('\n')
  37. ssr_paths = (self.decode_str(u[6:]) for u in ssr_urls)
  38. with open(self.cache_path, 'w') as c:
  39. fields = ['id', 'info', 'args']
  40. server_writer = csv.DictWriter(c, fieldnames=fields)
  41. server_writer.writeheader()
  42. for n, p in enumerate(ssr_paths):
  43. path, params = p.split('/?')
  44. d = self.decode_str
  45. host, port, proto, enc, obfs, passwd = path.split(':')
  46. raw_passwd = d(passwd)
  47. parsed_params = parse_qs(params)
  48. obfs_param = parsed_params.get('obfsparam', '')
  49. if obfs_param:
  50. obfs_param = d(obfs_param)
  51. proto_param = parsed_params.get('proto_param', '')
  52. if proto_param:
  53. proto_param = d(proto_param)
  54. name = d(parsed_params.get('remarks', ''),
  55. to_str=False).decode()
  56. group = d(parsed_params.get('group', ''),
  57. to_str=False).decode()
  58. args = f"-s {host} -p {port} -k {raw_passwd} -m {enc} -O {proto} -o {obfs} -b 127.0.0.1 -l 1080"
  59. if obfs_param:
  60. args = f"{args} -g {obfs_param}"
  61. if proto_param:
  62. args = f"{args} -G {proto_param}"
  63. server_writer.writerow({'id': n,
  64. 'args': args,
  65. 'info': f"{name} {group}"})
  66. def conn(self, node_id):
  67. with open(self.cache_path) as c:
  68. reader = csv.DictReader(c)
  69. ssr_args = None
  70. for row in reader:
  71. if row['id'] == str(node_id):
  72. ssr_args = row['args']
  73. os.system(f"{self.ssr_command} {ssr_args}")
  74. def ls(self):
  75. with open(self.cache_path) as c:
  76. reader = csv.DictReader(c)
  77. for row in reader:
  78. s = f"{row['id']}:{row['info']} "
  79. sys.stdout.write(s)
  80. cli = N3ROCLI()
  81. ls = cli.ls
  82. l = cli.ls
  83. conn = cli.conn
  84. c = cli.conn
  85. sync = cli.sync
  86. s = cli.sync