A simple cli for n3ro
You can not select more than 25 topics 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