xtlsapi-ipblacklist 3.3.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (278) hide show
  1. tests/__init__.py +0 -0
  2. tests/conftest.py +14 -0
  3. tests/test_base.py +5 -0
  4. tests/test_block_ips.py +9 -0
  5. tests/test_stats_online_ip_list.py +14 -0
  6. xtlsapi/VERSION +1 -0
  7. xtlsapi/__init__.py +4 -0
  8. xtlsapi/__main__.py +6 -0
  9. xtlsapi/__pycache__/__init__.cpython-313.pyc +0 -0
  10. xtlsapi/api_services/__init__.py +8 -0
  11. xtlsapi/api_services/_base.py +12 -0
  12. xtlsapi/api_services/handler/__init__.py +6 -0
  13. xtlsapi/api_services/handler/add_client.py +66 -0
  14. xtlsapi/api_services/handler/remove_client.py +27 -0
  15. xtlsapi/api_services/logger/__init__.py +5 -0
  16. xtlsapi/api_services/logger/restart_logger.py +17 -0
  17. xtlsapi/api_services/router/__init__.py +7 -0
  18. xtlsapi/api_services/router/block_ips.py +60 -0
  19. xtlsapi/api_services/stats/__init__.py +22 -0
  20. xtlsapi/api_services/stats/get_client_download_traffic.py +17 -0
  21. xtlsapi/api_services/stats/get_client_upload_traffic.py +15 -0
  22. xtlsapi/api_services/stats/get_inbound_download_traffic.py +16 -0
  23. xtlsapi/api_services/stats/get_inbound_upload_traffic.py +16 -0
  24. xtlsapi/api_services/stats/get_stats_online_ip_list.py +28 -0
  25. xtlsapi/api_services/stats/get_statsonline.py +18 -0
  26. xtlsapi/api_services/stats/get_statsquery.py +17 -0
  27. xtlsapi/api_services/stats/get_total_download_traffic.py +17 -0
  28. xtlsapi/api_services/stats/get_total_upload_traffic.py +16 -0
  29. xtlsapi/base.py +17 -0
  30. xtlsapi/cli.py +28 -0
  31. xtlsapi/client/SingboxClient.py +11 -0
  32. xtlsapi/client/XrayClient.py +11 -0
  33. xtlsapi/client/__init__.py +1 -0
  34. xtlsapi/client/__pycache__/XrayClient.cpython-313.pyc +0 -0
  35. xtlsapi/client/__pycache__/__init__.cpython-313.pyc +0 -0
  36. xtlsapi/exceptions/__init__.py +4 -0
  37. xtlsapi/exceptions/_base.py +3 -0
  38. xtlsapi/exceptions/email_already_exists.py +7 -0
  39. xtlsapi/exceptions/email_not_found.py +7 -0
  40. xtlsapi/exceptions/inbound_not_found.py +7 -0
  41. xtlsapi/ext/__init__.py +0 -0
  42. xtlsapi/ext/utils.py +49 -0
  43. xtlsapi/generate_from_xray_proto.py +81 -0
  44. xtlsapi/singbox_api/__init__.py +0 -0
  45. xtlsapi/singbox_api/build.sh +6 -0
  46. xtlsapi/singbox_api/extensions.proto +39 -0
  47. xtlsapi/singbox_api/extensions_pb2.py +31 -0
  48. xtlsapi/singbox_api/extensions_pb2_grpc.py +4 -0
  49. xtlsapi/singbox_api/stats.proto +63 -0
  50. xtlsapi/singbox_api/stats_old.proto +53 -0
  51. xtlsapi/singbox_api/stats_pb2.py +45 -0
  52. xtlsapi/singbox_api/stats_pb2_grpc.py +132 -0
  53. xtlsapi/singbox_api_services/__init__.py +6 -0
  54. xtlsapi/singbox_api_services/_base.py +7 -0
  55. xtlsapi/singbox_api_services/stats/__init__.py +18 -0
  56. xtlsapi/singbox_api_services/stats/get_client_download_traffic.py +17 -0
  57. xtlsapi/singbox_api_services/stats/get_client_upload_traffic.py +15 -0
  58. xtlsapi/singbox_api_services/stats/get_inbound_download_traffic.py +16 -0
  59. xtlsapi/singbox_api_services/stats/get_inbound_upload_traffic.py +16 -0
  60. xtlsapi/singbox_api_services/stats/get_statsquery.py +17 -0
  61. xtlsapi/singbox_api_services/stats/get_total_download_traffic.py +17 -0
  62. xtlsapi/singbox_api_services/stats/get_total_upload_traffic.py +16 -0
  63. xtlsapi/xray_api/__init__.py +0 -0
  64. xtlsapi/xray_api/a.sh +4 -0
  65. xtlsapi/xray_api/app/__init__.py +0 -0
  66. xtlsapi/xray_api/app/commander/__init__.py +0 -0
  67. xtlsapi/xray_api/app/commander/config_pb2.py +40 -0
  68. xtlsapi/xray_api/app/commander/config_pb2_grpc.py +24 -0
  69. xtlsapi/xray_api/app/dispatcher/__init__.py +0 -0
  70. xtlsapi/xray_api/app/dispatcher/config_pb2.py +39 -0
  71. xtlsapi/xray_api/app/dispatcher/config_pb2_grpc.py +24 -0
  72. xtlsapi/xray_api/app/dns/__init__.py +0 -0
  73. xtlsapi/xray_api/app/dns/config_pb2.py +51 -0
  74. xtlsapi/xray_api/app/dns/config_pb2_grpc.py +24 -0
  75. xtlsapi/xray_api/app/dns/fakedns/__init__.py +0 -0
  76. xtlsapi/xray_api/app/dns/fakedns/fakedns_pb2.py +39 -0
  77. xtlsapi/xray_api/app/dns/fakedns/fakedns_pb2_grpc.py +24 -0
  78. xtlsapi/xray_api/app/log/__init__.py +0 -0
  79. xtlsapi/xray_api/app/log/command/__init__.py +0 -0
  80. xtlsapi/xray_api/app/log/command/config_pb2.py +43 -0
  81. xtlsapi/xray_api/app/log/command/config_pb2_grpc.py +97 -0
  82. xtlsapi/xray_api/app/log/config_pb2.py +40 -0
  83. xtlsapi/xray_api/app/log/config_pb2_grpc.py +24 -0
  84. xtlsapi/xray_api/app/metrics/__init__.py +0 -0
  85. xtlsapi/xray_api/app/metrics/config_pb2.py +37 -0
  86. xtlsapi/xray_api/app/metrics/config_pb2_grpc.py +24 -0
  87. xtlsapi/xray_api/app/observatory/__init__.py +0 -0
  88. xtlsapi/xray_api/app/observatory/burst/config_pb2.py +39 -0
  89. xtlsapi/xray_api/app/observatory/burst/config_pb2_grpc.py +24 -0
  90. xtlsapi/xray_api/app/observatory/command/__init__.py +0 -0
  91. xtlsapi/xray_api/app/observatory/command/command_pb2.py +44 -0
  92. xtlsapi/xray_api/app/observatory/command/command_pb2_grpc.py +97 -0
  93. xtlsapi/xray_api/app/observatory/config_pb2.py +47 -0
  94. xtlsapi/xray_api/app/observatory/config_pb2_grpc.py +24 -0
  95. xtlsapi/xray_api/app/policy/__init__.py +0 -0
  96. xtlsapi/xray_api/app/policy/config_pb2.py +55 -0
  97. xtlsapi/xray_api/app/policy/config_pb2_grpc.py +24 -0
  98. xtlsapi/xray_api/app/proxyman/__init__.py +0 -0
  99. xtlsapi/xray_api/app/proxyman/command/__init__.py +0 -0
  100. xtlsapi/xray_api/app/proxyman/command/command_pb2.py +76 -0
  101. xtlsapi/xray_api/app/proxyman/command/command_pb2_grpc.py +398 -0
  102. xtlsapi/xray_api/app/proxyman/config_pb2.py +61 -0
  103. xtlsapi/xray_api/app/proxyman/config_pb2_grpc.py +24 -0
  104. xtlsapi/xray_api/app/reverse/__init__.py +0 -0
  105. xtlsapi/xray_api/app/reverse/config_pb2.py +45 -0
  106. xtlsapi/xray_api/app/reverse/config_pb2_grpc.py +24 -0
  107. xtlsapi/xray_api/app/router/__init__.py +0 -0
  108. xtlsapi/xray_api/app/router/command/__init__.py +0 -0
  109. xtlsapi/xray_api/app/router/command/command_pb2.py +73 -0
  110. xtlsapi/xray_api/app/router/command/command_pb2_grpc.py +312 -0
  111. xtlsapi/xray_api/app/router/config_pb2.py +70 -0
  112. xtlsapi/xray_api/app/router/config_pb2_grpc.py +24 -0
  113. xtlsapi/xray_api/app/stats/__init__.py +0 -0
  114. xtlsapi/xray_api/app/stats/command/__init__.py +0 -0
  115. xtlsapi/xray_api/app/stats/command/command.proto +62 -0
  116. xtlsapi/xray_api/app/stats/command/command_pb2.py +59 -0
  117. xtlsapi/xray_api/app/stats/command/command_pb2_grpc.py +269 -0
  118. xtlsapi/xray_api/app/stats/config_pb2.py +39 -0
  119. xtlsapi/xray_api/app/stats/config_pb2_grpc.py +24 -0
  120. xtlsapi/xray_api/common/__init__.py +0 -0
  121. xtlsapi/xray_api/common/log/__init__.py +0 -0
  122. xtlsapi/xray_api/common/log/log_pb2.py +37 -0
  123. xtlsapi/xray_api/common/log/log_pb2_grpc.py +24 -0
  124. xtlsapi/xray_api/common/net/__init__.py +0 -0
  125. xtlsapi/xray_api/common/net/address_pb2.py +37 -0
  126. xtlsapi/xray_api/common/net/address_pb2_grpc.py +24 -0
  127. xtlsapi/xray_api/common/net/destination_pb2.py +39 -0
  128. xtlsapi/xray_api/common/net/destination_pb2_grpc.py +24 -0
  129. xtlsapi/xray_api/common/net/network_pb2.py +39 -0
  130. xtlsapi/xray_api/common/net/network_pb2_grpc.py +24 -0
  131. xtlsapi/xray_api/common/net/port_pb2.py +39 -0
  132. xtlsapi/xray_api/common/net/port_pb2_grpc.py +24 -0
  133. xtlsapi/xray_api/common/protocol/__init__.py +0 -0
  134. xtlsapi/xray_api/common/protocol/headers_pb2.py +39 -0
  135. xtlsapi/xray_api/common/protocol/headers_pb2_grpc.py +24 -0
  136. xtlsapi/xray_api/common/protocol/server_spec_pb2.py +39 -0
  137. xtlsapi/xray_api/common/protocol/server_spec_pb2_grpc.py +24 -0
  138. xtlsapi/xray_api/common/protocol/user_pb2.py +38 -0
  139. xtlsapi/xray_api/common/protocol/user_pb2_grpc.py +24 -0
  140. xtlsapi/xray_api/common/serial/__init__.py +0 -0
  141. xtlsapi/xray_api/common/serial/typed_message_pb2.py +37 -0
  142. xtlsapi/xray_api/common/serial/typed_message_pb2_grpc.py +24 -0
  143. xtlsapi/xray_api/core/__init__.py +0 -0
  144. xtlsapi/xray_api/core/config_pb2.py +42 -0
  145. xtlsapi/xray_api/core/config_pb2_grpc.py +24 -0
  146. xtlsapi/xray_api/proxy/__init__.py +0 -0
  147. xtlsapi/xray_api/proxy/blackhole/__init__.py +0 -0
  148. xtlsapi/xray_api/proxy/blackhole/config_pb2.py +42 -0
  149. xtlsapi/xray_api/proxy/blackhole/config_pb2_grpc.py +24 -0
  150. xtlsapi/xray_api/proxy/dns/__init__.py +0 -0
  151. xtlsapi/xray_api/proxy/dns/config_pb2.py +38 -0
  152. xtlsapi/xray_api/proxy/dns/config_pb2_grpc.py +24 -0
  153. xtlsapi/xray_api/proxy/dokodemo/__init__.py +0 -0
  154. xtlsapi/xray_api/proxy/dokodemo/config_pb2.py +39 -0
  155. xtlsapi/xray_api/proxy/dokodemo/config_pb2_grpc.py +24 -0
  156. xtlsapi/xray_api/proxy/freedom/__init__.py +0 -0
  157. xtlsapi/xray_api/proxy/freedom/config_pb2.py +46 -0
  158. xtlsapi/xray_api/proxy/freedom/config_pb2_grpc.py +24 -0
  159. xtlsapi/xray_api/proxy/http/__init__.py +0 -0
  160. xtlsapi/xray_api/proxy/http/config_pb2.py +48 -0
  161. xtlsapi/xray_api/proxy/http/config_pb2_grpc.py +24 -0
  162. xtlsapi/xray_api/proxy/loopback/__init__.py +0 -0
  163. xtlsapi/xray_api/proxy/loopback/config_pb2.py +37 -0
  164. xtlsapi/xray_api/proxy/loopback/config_pb2_grpc.py +24 -0
  165. xtlsapi/xray_api/proxy/mtproto/__init__.py +0 -0
  166. xtlsapi/xray_api/proxy/mtproto/config_pb2.py +32 -0
  167. xtlsapi/xray_api/proxy/mtproto/config_pb2_grpc.py +4 -0
  168. xtlsapi/xray_api/proxy/shadowsocks/__init__.py +0 -0
  169. xtlsapi/xray_api/proxy/shadowsocks/config_pb2.py +46 -0
  170. xtlsapi/xray_api/proxy/shadowsocks/config_pb2_grpc.py +24 -0
  171. xtlsapi/xray_api/proxy/shadowsocks_2022/__init__.py +0 -0
  172. xtlsapi/xray_api/proxy/shadowsocks_2022/config_pb2.py +50 -0
  173. xtlsapi/xray_api/proxy/shadowsocks_2022/config_pb2_grpc.py +24 -0
  174. xtlsapi/xray_api/proxy/socks/__init__.py +0 -0
  175. xtlsapi/xray_api/proxy/socks/config_pb2.py +49 -0
  176. xtlsapi/xray_api/proxy/socks/config_pb2_grpc.py +24 -0
  177. xtlsapi/xray_api/proxy/trojan/__init__.py +0 -0
  178. xtlsapi/xray_api/proxy/trojan/config_pb2.py +45 -0
  179. xtlsapi/xray_api/proxy/trojan/config_pb2_grpc.py +24 -0
  180. xtlsapi/xray_api/proxy/vless/__init__.py +0 -0
  181. xtlsapi/xray_api/proxy/vless/account_pb2.py +37 -0
  182. xtlsapi/xray_api/proxy/vless/account_pb2_grpc.py +24 -0
  183. xtlsapi/xray_api/proxy/vless/encoding/__init__.py +0 -0
  184. xtlsapi/xray_api/proxy/vless/encoding/addons_pb2.py +37 -0
  185. xtlsapi/xray_api/proxy/vless/encoding/addons_pb2_grpc.py +24 -0
  186. xtlsapi/xray_api/proxy/vless/inbound/__init__.py +0 -0
  187. xtlsapi/xray_api/proxy/vless/inbound/config_pb2.py +40 -0
  188. xtlsapi/xray_api/proxy/vless/inbound/config_pb2_grpc.py +24 -0
  189. xtlsapi/xray_api/proxy/vless/outbound/__init__.py +0 -0
  190. xtlsapi/xray_api/proxy/vless/outbound/config_pb2.py +38 -0
  191. xtlsapi/xray_api/proxy/vless/outbound/config_pb2_grpc.py +24 -0
  192. xtlsapi/xray_api/proxy/vmess/__init__.py +0 -0
  193. xtlsapi/xray_api/proxy/vmess/account_pb2.py +38 -0
  194. xtlsapi/xray_api/proxy/vmess/account_pb2_grpc.py +24 -0
  195. xtlsapi/xray_api/proxy/vmess/inbound/__init__.py +0 -0
  196. xtlsapi/xray_api/proxy/vmess/inbound/config_pb2.py +42 -0
  197. xtlsapi/xray_api/proxy/vmess/inbound/config_pb2_grpc.py +24 -0
  198. xtlsapi/xray_api/proxy/vmess/outbound/__init__.py +0 -0
  199. xtlsapi/xray_api/proxy/vmess/outbound/config_pb2.py +38 -0
  200. xtlsapi/xray_api/proxy/vmess/outbound/config_pb2_grpc.py +24 -0
  201. xtlsapi/xray_api/proxy/wireguard/__init__.py +0 -0
  202. xtlsapi/xray_api/proxy/wireguard/config_pb2.py +41 -0
  203. xtlsapi/xray_api/proxy/wireguard/config_pb2_grpc.py +24 -0
  204. xtlsapi/xray_api/transport/__init__.py +0 -0
  205. xtlsapi/xray_api/transport/global/__init__.py +0 -0
  206. xtlsapi/xray_api/transport/global/config_pb2.py +30 -0
  207. xtlsapi/xray_api/transport/global/config_pb2_grpc.py +4 -0
  208. xtlsapi/xray_api/transport/internet/__init__.py +0 -0
  209. xtlsapi/xray_api/transport/internet/config_pb2.py +51 -0
  210. xtlsapi/xray_api/transport/internet/config_pb2_grpc.py +24 -0
  211. xtlsapi/xray_api/transport/internet/domainsocket/__init__.py +0 -0
  212. xtlsapi/xray_api/transport/internet/domainsocket/config_pb2.py +27 -0
  213. xtlsapi/xray_api/transport/internet/domainsocket/config_pb2_grpc.py +4 -0
  214. xtlsapi/xray_api/transport/internet/grpc/__init__.py +0 -0
  215. xtlsapi/xray_api/transport/internet/grpc/config_pb2.py +37 -0
  216. xtlsapi/xray_api/transport/internet/grpc/config_pb2_grpc.py +24 -0
  217. xtlsapi/xray_api/transport/internet/grpc/encoding/__init__.py +0 -0
  218. xtlsapi/xray_api/transport/internet/grpc/encoding/stream_pb2.py +41 -0
  219. xtlsapi/xray_api/transport/internet/grpc/encoding/stream_pb2_grpc.py +140 -0
  220. xtlsapi/xray_api/transport/internet/headers/__init__.py +0 -0
  221. xtlsapi/xray_api/transport/internet/headers/dns/config_pb2.py +37 -0
  222. xtlsapi/xray_api/transport/internet/headers/dns/config_pb2_grpc.py +24 -0
  223. xtlsapi/xray_api/transport/internet/headers/http/__init__.py +0 -0
  224. xtlsapi/xray_api/transport/internet/headers/http/config_pb2.py +49 -0
  225. xtlsapi/xray_api/transport/internet/headers/http/config_pb2_grpc.py +24 -0
  226. xtlsapi/xray_api/transport/internet/headers/noop/__init__.py +0 -0
  227. xtlsapi/xray_api/transport/internet/headers/noop/config_pb2.py +39 -0
  228. xtlsapi/xray_api/transport/internet/headers/noop/config_pb2_grpc.py +24 -0
  229. xtlsapi/xray_api/transport/internet/headers/srtp/__init__.py +0 -0
  230. xtlsapi/xray_api/transport/internet/headers/srtp/config_pb2.py +37 -0
  231. xtlsapi/xray_api/transport/internet/headers/srtp/config_pb2_grpc.py +24 -0
  232. xtlsapi/xray_api/transport/internet/headers/tls/__init__.py +0 -0
  233. xtlsapi/xray_api/transport/internet/headers/tls/config_pb2.py +37 -0
  234. xtlsapi/xray_api/transport/internet/headers/tls/config_pb2_grpc.py +24 -0
  235. xtlsapi/xray_api/transport/internet/headers/utp/__init__.py +0 -0
  236. xtlsapi/xray_api/transport/internet/headers/utp/config_pb2.py +37 -0
  237. xtlsapi/xray_api/transport/internet/headers/utp/config_pb2_grpc.py +24 -0
  238. xtlsapi/xray_api/transport/internet/headers/wechat/__init__.py +0 -0
  239. xtlsapi/xray_api/transport/internet/headers/wechat/config_pb2.py +37 -0
  240. xtlsapi/xray_api/transport/internet/headers/wechat/config_pb2_grpc.py +24 -0
  241. xtlsapi/xray_api/transport/internet/headers/wireguard/__init__.py +0 -0
  242. xtlsapi/xray_api/transport/internet/headers/wireguard/config_pb2.py +37 -0
  243. xtlsapi/xray_api/transport/internet/headers/wireguard/config_pb2_grpc.py +24 -0
  244. xtlsapi/xray_api/transport/internet/http/__init__.py +0 -0
  245. xtlsapi/xray_api/transport/internet/http/config_pb2.py +38 -0
  246. xtlsapi/xray_api/transport/internet/http/config_pb2_grpc.py +24 -0
  247. xtlsapi/xray_api/transport/internet/httpupgrade/config_pb2.py +41 -0
  248. xtlsapi/xray_api/transport/internet/httpupgrade/config_pb2_grpc.py +24 -0
  249. xtlsapi/xray_api/transport/internet/kcp/__init__.py +0 -0
  250. xtlsapi/xray_api/transport/internet/kcp/config_pb2.py +54 -0
  251. xtlsapi/xray_api/transport/internet/kcp/config_pb2_grpc.py +24 -0
  252. xtlsapi/xray_api/transport/internet/quic/__init__.py +0 -0
  253. xtlsapi/xray_api/transport/internet/quic/config_pb2.py +29 -0
  254. xtlsapi/xray_api/transport/internet/quic/config_pb2_grpc.py +4 -0
  255. xtlsapi/xray_api/transport/internet/reality/config_pb2.py +37 -0
  256. xtlsapi/xray_api/transport/internet/reality/config_pb2_grpc.py +24 -0
  257. xtlsapi/xray_api/transport/internet/splithttp/config_pb2.py +46 -0
  258. xtlsapi/xray_api/transport/internet/splithttp/config_pb2_grpc.py +24 -0
  259. xtlsapi/xray_api/transport/internet/tcp/__init__.py +0 -0
  260. xtlsapi/xray_api/transport/internet/tcp/config_pb2.py +38 -0
  261. xtlsapi/xray_api/transport/internet/tcp/config_pb2_grpc.py +24 -0
  262. xtlsapi/xray_api/transport/internet/tls/__init__.py +0 -0
  263. xtlsapi/xray_api/transport/internet/tls/config_pb2.py +41 -0
  264. xtlsapi/xray_api/transport/internet/tls/config_pb2_grpc.py +24 -0
  265. xtlsapi/xray_api/transport/internet/udp/__init__.py +0 -0
  266. xtlsapi/xray_api/transport/internet/udp/config_pb2.py +37 -0
  267. xtlsapi/xray_api/transport/internet/udp/config_pb2_grpc.py +24 -0
  268. xtlsapi/xray_api/transport/internet/websocket/__init__.py +0 -0
  269. xtlsapi/xray_api/transport/internet/websocket/config_pb2.py +41 -0
  270. xtlsapi/xray_api/transport/internet/websocket/config_pb2_grpc.py +24 -0
  271. xtlsapi/xray_api/transport/internet/xtls/__init__.py +0 -0
  272. xtlsapi/xray_api/transport/internet/xtls/config_pb2.py +30 -0
  273. xtlsapi/xray_api/transport/internet/xtls/config_pb2_grpc.py +4 -0
  274. xtlsapi_ipblacklist-3.3.2.dist-info/METADATA +58 -0
  275. xtlsapi_ipblacklist-3.3.2.dist-info/RECORD +278 -0
  276. xtlsapi_ipblacklist-3.3.2.dist-info/WHEEL +5 -0
  277. xtlsapi_ipblacklist-3.3.2.dist-info/licenses/LICENSE +24 -0
  278. xtlsapi_ipblacklist-3.3.2.dist-info/top_level.txt +2 -0
tests/__init__.py ADDED
File without changes
tests/conftest.py ADDED
@@ -0,0 +1,14 @@
1
+ import sys
2
+ import pytest
3
+
4
+
5
+ # each test runs on cwd to its temp dir
6
+ @pytest.fixture(autouse=True)
7
+ def go_to_tmpdir(request):
8
+ # Get the fixture dynamically by its name.
9
+ tmpdir = request.getfixturevalue("tmpdir")
10
+ # ensure local test created packages can be imported
11
+ sys.path.insert(0, str(tmpdir))
12
+ # Chdir only for the duration of the test.
13
+ with tmpdir.as_cwd():
14
+ yield
tests/test_base.py ADDED
@@ -0,0 +1,5 @@
1
+ from xtlsapi.base import NAME
2
+
3
+
4
+ def test_base():
5
+ assert NAME == "xtlsapi"
@@ -0,0 +1,9 @@
1
+ import pytest
2
+ from unittest.mock import patch
3
+ from xtlsapi import XrayClient
4
+
5
+ def test_stats_online_ip_list():
6
+ xray = XrayClient("127.0.0.1", 53357)
7
+ with patch.object(xray, 'stats_online_ip_list', return_value={'212.58.119.246': 1763418412}):
8
+ result = xray.stats_online_ip_list("1")
9
+ assert result == {'212.58.119.246': 1763418412}
@@ -0,0 +1,14 @@
1
+ import pytest
2
+ from unittest.mock import patch
3
+ from xtlsapi import XrayClient
4
+ from xtlsapi.xray_api.app.router.command import command_pb2
5
+
6
+
7
+ def test_stats_online_ip_list():
8
+ xray = XrayClient("127.0.0.1", 53357)
9
+ with patch.object(xray, 'block_ips', return_value=command_pb2.AddRuleResponse()):
10
+ xray.block_ips(
11
+ ips=["103.23.202.74"],
12
+ inbound_tag="vless-in"
13
+ )
14
+ assert xray
xtlsapi/VERSION ADDED
@@ -0,0 +1 @@
1
+ 3.3.0
xtlsapi/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ from xtlsapi.client.XrayClient import XrayClient
2
+ from xtlsapi.client.SingboxClient import SingboxClient
3
+ import xtlsapi.exceptions
4
+ from xtlsapi.ext import utils
xtlsapi/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Entry point for xtlsapi."""
2
+
3
+ from .cli import main # pragma: no cover
4
+
5
+ if __name__ == "__main__": # pragma: no cover
6
+ main()
@@ -0,0 +1,8 @@
1
+ from .stats import StatsAPIService
2
+ from .handler import HandlerAPIService
3
+ from .logger import LoggerAPIService
4
+ from .router import RouterAPIService
5
+
6
+
7
+ class APIService(StatsAPIService, HandlerAPIService, LoggerAPIService, RouterAPIService):
8
+ pass
@@ -0,0 +1,12 @@
1
+ from xtlsapi.xray_api.app.log.command import config_pb2_grpc as logger_pb2_grpc
2
+ from xtlsapi.xray_api.app.stats.command import command_pb2_grpc as stats_pb2_grpc
3
+ from xtlsapi.xray_api.app.proxyman.command import command_pb2_grpc as handler_pb2_grpc
4
+ from xtlsapi.xray_api.app.router.command import command_pb2_grpc as router_pb2_grpc
5
+
6
+
7
+ class BaseService:
8
+ def __init__(self):
9
+ self.stats_stub = stats_pb2_grpc.StatsServiceStub(self._channel)
10
+ self.logger_stub = logger_pb2_grpc.LoggerServiceStub(self._channel)
11
+ self.handler_stub = handler_pb2_grpc.HandlerServiceStub(self._channel)
12
+ self.routing_stub = router_pb2_grpc.RoutingServiceStub(self._channel)
@@ -0,0 +1,6 @@
1
+ from .add_client import AddClient
2
+ from .remove_client import RemoveClient
3
+
4
+
5
+ class HandlerAPIService(AddClient, RemoveClient):
6
+ pass
@@ -0,0 +1,66 @@
1
+ from grpc._channel import _InactiveRpcError
2
+
3
+ from xtlsapi.xray_api.common.protocol import user_pb2
4
+ from xtlsapi.xray_api.app.proxyman.command import command_pb2
5
+ from xtlsapi.ext import utils
6
+ from .._base import BaseService
7
+ from xtlsapi import exceptions
8
+
9
+
10
+ class AddClient(BaseService):
11
+ def add_client(self, inbound_tag, user_id_or_password, email,protocol='vless', level=None, alter_id=None,flow=None,cipher=None):
12
+ try:
13
+ if protocol=='vmess':
14
+ from xtlsapi.xray_api.proxy.vmess import account_pb2
15
+ account=account_pb2.Account(id=user_id_or_password)
16
+ elif protocol=='vless':
17
+ from xtlsapi.xray_api.proxy.vless import account_pb2
18
+ account=account_pb2.Account(id=user_id_or_password,flow=flow,encryption="none")
19
+ elif protocol=='trojan':
20
+ from xtlsapi.xray_api.proxy.trojan import config_pb2
21
+ account=config_pb2.Account(password=user_id_or_password,flow=flow)
22
+ elif protocol=='shadowsocks':
23
+ from xtlsapi.xray_api.proxy.shadowsocks import config_pb2
24
+ cipher_map={'aes_128_gcm':config_pb2.CipherType.AES_128_GCM,
25
+ 'aes_256_gcm':config_pb2.CipherType.AES_256_GCM,
26
+ 'chacha20_poly1305':config_pb2.CipherType.CHACHA20_POLY1305,
27
+ 'xchacha20_poly1305':config_pb2.CipherType.XCHACHA20_POLY1305,
28
+ None:config_pb2.CipherType.NONE
29
+ }
30
+ account=config_pb2.Account(password=user_id_or_password,cipher_type=cipher_map.get(cipher,cipher_map[None]))
31
+ # elif protocol=='shadowsocks_2022':
32
+ # from xtlsapi.xray_api.proxy.shadowsocks import config_pb2
33
+ # cipher_map={'aes_128_gcm':config_pb2.CipherType.AES_128_GCM,
34
+ # 'aes_256_gcm':config_pb2.CipherType.AES_256_GCM,
35
+ # 'chacha20_poly1305':config_pb2.CipherType.CHACHA20_POLY1305,
36
+ # 'xchacha20_poly1305':config_pb2.CipherType.XCHACHA20_POLY1305,
37
+ # None:config_pb2.CipherType.NONE
38
+ # }
39
+ # account=config_pb2.Account(password=user_id_or_password,cipher_type=cipher_map.get(cipher,cipher_map[None])
40
+ # raise Exception("not implemented ")
41
+ else:
42
+ raise Exception("not implemented "+protocol )
43
+
44
+ self.handler_stub.AlterInbound(
45
+ command_pb2.AlterInboundRequest(
46
+ tag=inbound_tag,
47
+ operation=utils.to_typed_message(
48
+ command_pb2.AddUserOperation(
49
+ user=user_pb2.User(
50
+ email=email,
51
+ level=level,
52
+ account=utils.to_typed_message(account),
53
+ )
54
+ )
55
+ ),
56
+ )
57
+ )
58
+ return user_id_or_password
59
+ except _InactiveRpcError as e:
60
+ details = e.details()
61
+ if details.endswith(f"User {email} already exists."):
62
+ raise exceptions.EmailAlreadyExists(details, email)
63
+ elif details.endswith(f"handler not found: {inbound_tag}"):
64
+ raise exceptions.InboundNotFound(details, inbound_tag)
65
+ else:
66
+ raise exceptions.XRayException(details)
@@ -0,0 +1,27 @@
1
+ from grpc._channel import _InactiveRpcError
2
+ from xtlsapi.ext import utils
3
+ from xtlsapi import exceptions
4
+ from xtlsapi.xray_api.app.proxyman.command import command_pb2
5
+
6
+ from .._base import BaseService
7
+
8
+
9
+ class RemoveClient(BaseService):
10
+ def remove_client(self, inbound_tag, email):
11
+ try:
12
+ self.handler_stub.AlterInbound(
13
+ command_pb2.AlterInboundRequest(
14
+ tag=inbound_tag,
15
+ operation=utils.to_typed_message(
16
+ command_pb2.RemoveUserOperation(email=email)
17
+ ),
18
+ )
19
+ )
20
+ except _InactiveRpcError as e:
21
+ details = e.details()
22
+ if details.endswith(f"User {email} not found."):
23
+ raise exceptions.EmailNotFound(details, email)
24
+ elif details.endswith(f"handler not found: {inbound_tag}"):
25
+ raise exceptions.InboundNotFound(details, inbound_tag)
26
+ else:
27
+ raise exceptions.XRayException(details)
@@ -0,0 +1,5 @@
1
+ from .restart_logger import RestartLogger
2
+
3
+
4
+ class LoggerAPIService(RestartLogger):
5
+ pass
@@ -0,0 +1,17 @@
1
+ from grpc._channel import _InactiveRpcError
2
+
3
+ from xtlsapi import exceptions
4
+ from xtlsapi.xray_api.app.log.command import config_pb2
5
+
6
+ from .._base import BaseService
7
+
8
+
9
+ class RestartLogger(BaseService):
10
+ def restart_logger(self):
11
+ try:
12
+ self.logger_stub.RestartLogger(
13
+ config_pb2.RestartLoggerRequest()
14
+ )
15
+ except _InactiveRpcError as e:
16
+ details = e.details()
17
+ raise exceptions.XRayException(details)
@@ -0,0 +1,7 @@
1
+ from .block_ips import RouterBlockIps
2
+
3
+
4
+ class RouterAPIService(
5
+ RouterBlockIps,
6
+ ):
7
+ pass
@@ -0,0 +1,60 @@
1
+ import grpc
2
+ import ipaddress
3
+
4
+ from xtlsapi.api_services._base import BaseService
5
+ from xtlsapi.xray_api.app.router.command import command_pb2
6
+ from xtlsapi.xray_api.common.serial import typed_message_pb2
7
+ from xtlsapi.xray_api.app.router import config_pb2
8
+
9
+
10
+ class RouterBlockIps(BaseService):
11
+
12
+ def block_ips(
13
+ self,
14
+ ips: list[str],
15
+ inbound_tag: str,
16
+ rule_tag: str = "sourceIpBlock",
17
+ outbound_tag: str = "blocked",
18
+ ):
19
+ try:
20
+ self.routing_stub.RemoveRule(
21
+ command_pb2.RemoveRuleRequest(ruleTag=rule_tag)
22
+ )
23
+
24
+ if not ips:
25
+ return None
26
+
27
+ rule = config_pb2.RoutingRule()
28
+ rule.rule_tag = rule_tag
29
+ rule.inbound_tag.extend([inbound_tag] if inbound_tag else [])
30
+ rule.tag = outbound_tag
31
+
32
+ for ip in ips:
33
+ net = ipaddress.ip_network(ip, strict=False)
34
+
35
+ cidr = config_pb2.CIDR()
36
+ cidr.ip = net.network_address.packed
37
+ cidr.prefix = net.prefixlen
38
+
39
+ geo = config_pb2.GeoIP()
40
+ geo.cidr.append(cidr)
41
+
42
+ rule.source_geoip.append(geo)
43
+
44
+ config = config_pb2.Config()
45
+ config.rule.append(rule)
46
+
47
+ typed_msg = typed_message_pb2.TypedMessage(
48
+ type="xray.app.router.Config",
49
+ value=config.SerializeToString(),
50
+ )
51
+
52
+ return self.routing_stub.AddRule(
53
+ command_pb2.AddRuleRequest(
54
+ config=typed_msg,
55
+ shouldAppend=True,
56
+ )
57
+ )
58
+
59
+ except grpc.RpcError as e:
60
+ raise e
@@ -0,0 +1,22 @@
1
+ from .get_client_upload_traffic import GetClientUploadTraffic
2
+ from .get_client_download_traffic import GetClientDownloadTraffic
3
+ from .get_inbound_upload_traffic import GetInboundUploadTraffic
4
+ from .get_inbound_download_traffic import GetInboundDownloadTraffic
5
+ from .get_total_upload_traffic import GetTotalUploadTraffic
6
+ from .get_total_download_traffic import GetTotalDownloadTraffic
7
+ from .get_statsquery import StatsQuery
8
+ from .get_statsonline import StatsOnline
9
+ from .get_stats_online_ip_list import StatsOnlineIpList
10
+
11
+ class StatsAPIService(
12
+ GetClientUploadTraffic,
13
+ GetClientDownloadTraffic,
14
+ GetInboundUploadTraffic,
15
+ GetInboundDownloadTraffic,
16
+ GetTotalUploadTraffic,
17
+ GetTotalDownloadTraffic,
18
+ StatsQuery,
19
+ StatsOnline,
20
+ StatsOnlineIpList
21
+ ):
22
+ pass
@@ -0,0 +1,17 @@
1
+ import grpc
2
+ from xtlsapi.xray_api.app.stats.command import command_pb2
3
+
4
+ from .._base import BaseService
5
+
6
+
7
+ class GetClientDownloadTraffic(BaseService):
8
+ def get_client_download_traffic(self, email, reset=False):
9
+ try:
10
+ return self.stats_stub.GetStats(
11
+ command_pb2.GetStatsRequest(
12
+ name=f"user>>>{email}>>>traffic>>>downlink", reset=reset
13
+ )
14
+ ).stat.value
15
+ except grpc.RpcError:
16
+ # raise
17
+ return None
@@ -0,0 +1,15 @@
1
+ import grpc
2
+ from xtlsapi.xray_api.app.stats.command import command_pb2
3
+ from .._base import BaseService
4
+
5
+
6
+ class GetClientUploadTraffic(BaseService):
7
+ def get_client_upload_traffic(self, email, reset=False):
8
+ try:
9
+ return self.stats_stub.GetStats(
10
+ command_pb2.GetStatsRequest(
11
+ name=f"user>>>{email}>>>traffic>>>uplink", reset=reset
12
+ )
13
+ ).stat.value
14
+ except grpc.RpcError:
15
+ return None
@@ -0,0 +1,16 @@
1
+ import grpc
2
+ from xtlsapi.xray_api.app.stats.command import command_pb2
3
+ from .._base import BaseService
4
+
5
+
6
+ class GetInboundDownloadTraffic(BaseService):
7
+ def get_inbound_download_traffic(self, tag, reset=False):
8
+ try:
9
+ return self.stats_stub.GetStats(
10
+ command_pb2.GetStatsRequest(
11
+ name=f"inbound>>>{tag}>>>traffic>>>downlink", reset=reset
12
+ )
13
+ ).stat.value
14
+ except grpc.RpcError:
15
+ # raise
16
+ return None
@@ -0,0 +1,16 @@
1
+ import grpc
2
+ from xtlsapi.xray_api.app.stats.command import command_pb2
3
+ from .._base import BaseService
4
+
5
+
6
+ class GetInboundUploadTraffic(BaseService):
7
+ def get_inbound_upload_traffic(self, tag, reset=False):
8
+ try:
9
+ return self.stats_stub.GetStats(
10
+ command_pb2.GetStatsRequest(
11
+ name=f"inbound>>>{tag}>>>traffic>>>uplink", reset=reset
12
+ )
13
+ ).stat.value
14
+ except grpc.RpcError:
15
+ # raise
16
+ return None
@@ -0,0 +1,28 @@
1
+ import grpc
2
+ from xtlsapi.xray_api.app.stats.command import command_pb2
3
+
4
+ from .._base import BaseService
5
+
6
+
7
+ class StatsOnlineIpList(BaseService):
8
+ def stats_online_ip_list(self, user, reset=False) -> dict:
9
+ """
10
+ Returns a dictionary of online IPs for the given user.
11
+
12
+ Args:
13
+ user: The email of the user to query.
14
+
15
+ Returns:
16
+ A dictionary mapping IP addresses to last cleanup time of expired ip's.
17
+ """
18
+
19
+ try:
20
+ return self.stats_stub.GetStatsOnlineIpList(
21
+ command_pb2.GetStatsRequest(
22
+ name=f"user>>>{user}>>>online",
23
+ reset=reset
24
+ )
25
+ ).ips
26
+ except grpc.RpcError:
27
+ raise
28
+ return None
@@ -0,0 +1,18 @@
1
+ import grpc
2
+ from xtlsapi.xray_api.app.stats.command import command_pb2
3
+
4
+ from .._base import BaseService
5
+
6
+
7
+ class StatsOnline(BaseService):
8
+ def stats_online(self, user,reset=False):
9
+ try:
10
+ return self.stats_stub.GetStatsOnline(
11
+ command_pb2.GetStatsRequest(
12
+ name=f"user>>>{user}>>>online",
13
+ reset=reset
14
+ )
15
+ ).stat.value
16
+ except grpc.RpcError:
17
+ raise
18
+ return None
@@ -0,0 +1,17 @@
1
+ import grpc
2
+ from xtlsapi.xray_api.app.stats.command import command_pb2
3
+
4
+ from .._base import BaseService
5
+
6
+
7
+ class StatsQuery(BaseService):
8
+ def stats_query(self, pattern,reset=False):
9
+ try:
10
+ return self.stats_stub.QueryStats(
11
+ command_pb2.QueryStatsRequest(
12
+ pattern=pattern,reset=reset
13
+ )
14
+ ).stat
15
+ except grpc.RpcError:
16
+ raise
17
+ return None
@@ -0,0 +1,17 @@
1
+ import grpc
2
+ from xtlsapi.xray_api.app.stats.command import command_pb2
3
+ from .._base import BaseService
4
+
5
+
6
+ class GetTotalDownloadTraffic(BaseService):
7
+ def get_total_download_traffic(self, reset=False):
8
+ raise Exception('Not Implemented')
9
+ try:
10
+ return self.stats_stub.GetStats(
11
+ command_pb2.GetStatsRequest(
12
+ name=f"outbound>>>statout>>>traffic>>>downlink", reset=reset
13
+ )
14
+ ).stat.value
15
+ except grpc.RpcError:
16
+ # raise
17
+ return None
@@ -0,0 +1,16 @@
1
+ import grpc
2
+ from xtlsapi.xray_api.app.stats.command import command_pb2
3
+ from .._base import BaseService
4
+
5
+
6
+ class GetTotalUploadTraffic(BaseService):
7
+ def get_total_upload_traffic(self, reset=False):
8
+ raise Exception('Not Implemented')
9
+ try:
10
+ return self.stats_stub.GetStats(
11
+ command_pb2.GetStatsRequest(
12
+ name=f"outbound>>>direct>>>traffic>>>uplink", reset=reset
13
+ )
14
+ ).stat.value
15
+ except grpc.RpcError:
16
+ return None
xtlsapi/base.py ADDED
@@ -0,0 +1,17 @@
1
+ """
2
+ xtlsapi base module.
3
+
4
+ This is the principal module of the xtlsapi project.
5
+ here you put your main classes and objects.
6
+
7
+ Be creative! do whatever you want!
8
+
9
+ If you want to replace this with a Flask application run:
10
+
11
+ $ make init
12
+
13
+ and then choose `flask` as template.
14
+ """
15
+
16
+ # example constant variable
17
+ NAME = "xtlsapi"
xtlsapi/cli.py ADDED
@@ -0,0 +1,28 @@
1
+ """CLI interface for xtlsapi project.
2
+
3
+ Be creative! do whatever you want!
4
+
5
+ - Install click or typer and create a CLI app
6
+ - Use builtin argparse
7
+ - Start a web application
8
+ - Import things from your .base module
9
+ """
10
+
11
+
12
+ def main(): # pragma: no cover
13
+ """
14
+ The main function executes on commands:
15
+ `python -m xtlsapi` and `$ xtlsapi `.
16
+
17
+ This is your program's entry point.
18
+
19
+ You can change this function to do whatever you want.
20
+ Examples:
21
+ * Run a test suite
22
+ * Run a server
23
+ * Do some other stuff
24
+ * Run a command line application (Click, Typer, ArgParse)
25
+ * List all available tasks
26
+ * Run an application (Flask, FastAPI, Django, etc.)
27
+ """
28
+ print("This will do something")
@@ -0,0 +1,11 @@
1
+ from grpc import insecure_channel as grpc_insecure_channel
2
+
3
+ from xtlsapi.singbox_api_services import APIService
4
+
5
+
6
+ class SingboxClient(APIService):
7
+ def __init__(self, host, port):
8
+ self.host = host
9
+ self.port = port
10
+ self._channel = grpc_insecure_channel(f'{host}:{port}')
11
+ super().__init__()
@@ -0,0 +1,11 @@
1
+ from grpc import insecure_channel as grpc_insecure_channel
2
+
3
+ from xtlsapi.api_services import APIService
4
+
5
+
6
+ class XrayClient(APIService):
7
+ def __init__(self, host, port):
8
+ self.host = host
9
+ self.port = port
10
+ self._channel = grpc_insecure_channel(f'{host}:{port}')
11
+ super().__init__()
@@ -0,0 +1 @@
1
+ from .XrayClient import XrayClient
@@ -0,0 +1,4 @@
1
+ from ._base import XRayException
2
+ from .email_not_found import EmailNotFound
3
+ from .inbound_not_found import InboundNotFound
4
+ from .email_already_exists import EmailAlreadyExists
@@ -0,0 +1,3 @@
1
+ class XRayException(Exception):
2
+ def __init__(self, details):
3
+ self.details = details
@@ -0,0 +1,7 @@
1
+ from ._base import XRayException
2
+
3
+
4
+ class EmailAlreadyExists(XRayException):
5
+ def __init__(self, details, email):
6
+ self.email = email
7
+ super().__init__(details)
@@ -0,0 +1,7 @@
1
+ from ._base import XRayException
2
+
3
+
4
+ class EmailNotFound(XRayException):
5
+ def __init__(self, details, email):
6
+ self.email = email
7
+ super().__init__(details)
@@ -0,0 +1,7 @@
1
+ from ._base import XRayException
2
+
3
+
4
+ class InboundNotFound(XRayException):
5
+ def __init__(self, details, inbound_tag):
6
+ self.inbound_tag = inbound_tag
7
+ super().__init__(details)
File without changes
xtlsapi/ext/utils.py ADDED
@@ -0,0 +1,49 @@
1
+ import uuid
2
+ import math
3
+ import socket
4
+ import secrets
5
+
6
+ from xtlsapi.xray_api.common.serial import typed_message_pb2
7
+
8
+
9
+ def to_typed_message(message):
10
+ return typed_message_pb2.TypedMessage(
11
+ type=message.DESCRIPTOR.full_name, value=message.SerializeToString()
12
+ )
13
+
14
+
15
+ def ip2bytes(ip: str):
16
+ return bytes([int(i) for i in ip.split('.')])
17
+
18
+
19
+ def generate_random_tag():
20
+ return secrets.token_urlsafe()
21
+
22
+
23
+ def generate_random_name(hex_count=8):
24
+ return f"{secrets.token_hex(hex_count)}"
25
+
26
+
27
+ def generate_random_user_id():
28
+ return uuid.uuid4().hex
29
+
30
+
31
+ def generate_random_email(tld='vump.com', hex_count=8):
32
+ return f"{generate_random_name(hex_count)}@{tld}"
33
+
34
+
35
+ def generate_random_port():
36
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as tcp:
37
+ tcp.bind(('', 0))
38
+ addr, port = tcp.getsockname()
39
+ return port
40
+
41
+
42
+ def human_readable_bytes(size_bytes):
43
+ if not size_bytes:
44
+ return "0 B"
45
+ size_name = ("B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB")
46
+ i = int(math.floor(math.log(size_bytes, 1024)))
47
+ p = math.pow(1024, i)
48
+ s = round(size_bytes / p, 2)
49
+ return f"{s} {size_name[i]}"