├── README.md ├── README_en.md ├── img ├── 1 ├── 1.png ├── 1111.png ├── 2.png ├── 222.png ├── 2222.png ├── 222en.png ├── 3.png ├── 333.png ├── 3333.png ├── 333en.png ├── 4.png ├── 444.png ├── 4444.png ├── 444en.png ├── 5.png ├── 555.png ├── 5555.png ├── 555en.png ├── 666.png ├── 6666.png ├── 666en.png ├── 777.png ├── 777en.png ├── 888.png └── 999.png ├── main.py ├── main.yml └── main_En.py /README.md: -------------------------------------------------------------------------------- 1 | # WaterDragon 水龙 v1.0 2 | 和水一样 灵活多变, 3 | 4 | 5 | # 建议用小号跑 大号容易封号 6 | # 如果手头有多余邮箱的 可以多注册几个github号来跑这个 7 | 8 | 像龙一样 来去自如 9 | ## 用Github Action实现IP代理功能 也可翻墙 10 | ### 核心 11 | 这个项目的**核心是NPS[https://github.com/ehang-io/nps] + Github Action** 12 | Github Action和SCF实现代理池的方式不一样:**SCF可以用网关触发,但是Action不是**,Action是给你提供了一台可出不可入的如同私人电脑一般的一个虚拟环境,所以我们如果要想用代理到Action然后去访问 就要我们的**vps 帮忙,先做个穿透,然后转发** 13 | ## Tips:代理出去的IP是微软云的 而且IP众多 也不容易被ban 14 | # 使用方法 15 | 16 | #### 1.在vps上装nps并配置 17 | 下载地址 [https://github.com/ehang-io/nps/releases/tag/v0.26.10](https://github.com/ehang-io/nps/releases/tag/v0.26.10) 18 | 下载合适的版本 这里下载的是linux_amd64_server.tar.gz 19 | 执行`tar -axvf linux_amd64_server.tar.gz`进行解压 20 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/222.png) 21 | #### 2.然后去修改配置 22 | `cd conf` 23 | `vim nps.conf` 24 | 我们修改一共2个东西 25 | ###### ①.首先是 web_password 26 | **这个改的越复杂越好** 是nps的管理面板 不过这里不用gui的 用的是webapi,用不到gui的密码,如果是默认的123,会被有心人搞破坏 27 | ###### ②.然后是这里 28 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/333.png) 29 | 把`auth_key`前面的注释去掉,然后修改auth_key的值 30 | 然后把`auth_crypt_key`修改为别的16位长度的一个字符串 (默认也可以 31 | **然后把auth_key 记住备用** 32 | ##### ③.http_proxy_port 33 | 可改可不改 **改了是防止http监听端口与apache,nginx这些服务冲突** 34 | ##### ④.web_port 35 | **api的地址**,监听的是8080端口 如果8080与本地软件有冲突则更改(按需更改),如果改过就是 vps的ip:web_port 36 | 然后回到上级目录`cd .. ` 37 | 随后让nps运行` ./nps` 38 | 如果正常未出现问题 就可以把nps挂后台然后进行 下一步了 39 | `nohup ./nps &` 40 | #### 3.获取github_token 41 | ##### 前往[https://github.com/settings/tokens](https://github.com/settings/tokens) 42 | 43 | ### 里面勾勾要全勾上哦 44 | 45 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/444.png) 46 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/555.png) 47 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/666.png) 48 | **记住备用** 49 | #### 配置脚本 50 | 首先下载脚本 51 | `git clone https://github.com/sh3d0ww01f/WaterDragon.git` 52 | 然后修改`main.py`文件 53 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/777.png) 54 | ①**api的位置填上自己的api地址(http://vps_ip:web_port,如果没改过前面的web_port 则就是http://vps_ip:8080)** 55 | ②**auth_key 写上更改过的auth_key** 56 | ③**token写github获取的token** 57 | # 运行脚本 58 | `python3 main.py` 59 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/888.png) 60 | **①.输入socks5 进入隧道管理 我们需要先加一个** 61 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/999.png) 62 | 出现成功连接WebApi则说明api配置正确 63 | **②.输入add 增加socks5隧道** 64 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/1111.png) 65 | **密钥随意写,端口只要外网能通就可以,加密的话1代表要加密,0代表不加密** 66 | **③.配置好了新隧道,我们回到菜单使用** 67 | 输入 `back` 回到菜单,然后**键入`manager`进入Github Action管理** 68 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/2222.png) 69 | 输入`select`选择要连接的socks5隧道 70 | 这里选择新增的 客户端ID为21的 71 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/3333.png) 72 | 73 | 出现`start success`即为启动成功 74 | 75 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/4444.png) 76 | 配置一下 配置好 就可以用这个代理了 77 | 78 | # 效果 79 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/2.png) 80 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/3.png) 81 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/4.png) 82 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/5.png) 83 | # 停止Action 84 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/5555.png) 85 | 然后键入0 即可暂停现在运行中的GithubAction机子 86 | 出现“取消运行成功” 则代表成功暂停运行 87 | # 后序 88 | Action和SCF不一样 没有多出口 但是可以多开Action,然后实现多ip访问的目的 89 | 90 | -------------------------------------------------------------------------------- /README_en.md: -------------------------------------------------------------------------------- 1 | # WaterDragon v1.0 2 | ## Use Github Action to achieve proxy function 3 | ### Core 4 | This project **is based on NPS[https://github.com/ehang-io/nps] + Github Action** 5 | ## Tips:If you use it ,you can get a large number of IP because GithubAction is supported by MicroSoftCloud,it's really a "fertile soil" 6 | # Usage 7 | 8 | #### 1.Install NPS on our vps 9 | download it first [https://github.com/ehang-io/nps/releases/tag/v0.26.10](https://github.com/ehang-io/nps/releases/tag/v0.26.10) 10 | 11 | download appropriate version, I download `linux_amd64_server.tar.gz` for example 12 | 13 | execute `tar -axvf linux_amd64_server.tar.gz`to unzip 14 | 15 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/222.png) 16 | 17 | #### 2.Then we should modify config 18 | `cd conf` 19 | 20 | `vim nps.conf` 21 | 22 | we change these two files in total 23 | 24 | ###### ①. Change web_password 25 | **change it as complex as we can** it is password of nps-gui,but I will use its WebApi instead of nps-gui, so if you use adopt deafult password,you maybe get attack by others 26 | ###### ②.Open WebApi Mode 27 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/333.png) 28 | 29 | remove the comment before `auth_key`,and change the value of `auth_key` 30 | 31 | **advice:** change `auth_crypt_key` 32 | 33 | **then remember the auth_key we changed and hold it in reserve for next step ** 34 | ##### ③.http_proxy_port 35 | Advice:U had batter to change it ,because it maybe conflict with the service which listen 80 port **such as apache,nginx** 36 | ##### ④.web_port 37 | **Some information of api** , it listen 8080 port if you never change it ,otherwise the address of Api is: vps_ip:web_port 38 | then we execute `cd .. ` and ` ./nps` 39 | If NPS can start successfully ,you can let it runs in the background:`nohup ./nps &` 40 | #### 3.Get Github_Token 41 | ##### GOTO[https://github.com/settings/tokens](https://github.com/settings/tokens)and Operate according to the images below 42 | 43 | 44 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/444.png) 45 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/555.png) 46 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/666.png) 47 | **You need to remember them for next step** 48 | #### Modify Script 49 | Firstly,we download the script: 50 | `git clone https://github.com/sh3d0ww01f/WaterDragon.git` 51 | and then modify file named `main_En.py` 52 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/777.png) 53 | ①**type the address of your Api :api(http://vps_ip:web_port,if u neven change web_port, the Api is http://vps_ip:8080)** 54 | 55 | ②**type your auth_key behind** 56 | 57 | ③**type your token ** 58 | 59 | # Run the script 60 | `python3 main_En.py` 61 | 62 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/111en.png) 63 | 64 | **①.Type socks5 to enter socks5 manager, we need to add it first** 65 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/222en.png) 66 | 67 | if "Connect WebApi successfully" appear,it means the config of your api is corrent 68 | 69 | **②.type add to add a new socsk5 client** 70 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/333en.png) 71 | **you can set ListenPort wantonly as long as you can connect it.Besides 1 (encryption),0(No encryption)** 72 | **③.Now we creat socks5 client , let us use it ** 73 | 74 | type `back` to back 'menu',and then type **`manager` to enter Github Action Manager** 75 | 76 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/444en.png) 77 | 78 | type `select` to select the socks5 client you want to connect 79 | 80 | I choose No. 19 as an example 81 | 82 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/555en.png) 83 | 84 | when it appear `start success` , it means start successfully 85 | 86 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/4444.png) 87 | 88 | 89 | then we connect it 90 | 91 | # Result 92 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/2.png) 93 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/3.png) 94 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/4.png) 95 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/5.png) 96 | # How to Stop Action 97 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/666en.png) 98 | ![](https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/main/img/777en.png) 99 | 100 | 101 | then we type "0" to stop the GithubAction which in_progress 102 | 103 | 104 | if "stop process succcessfully" ,that means stop successfully 105 | -------------------------------------------------------------------------------- /img/1: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/1.png -------------------------------------------------------------------------------- /img/1111.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/1111.png -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/2.png -------------------------------------------------------------------------------- /img/222.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/222.png -------------------------------------------------------------------------------- /img/2222.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/2222.png -------------------------------------------------------------------------------- /img/222en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/222en.png -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/3.png -------------------------------------------------------------------------------- /img/333.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/333.png -------------------------------------------------------------------------------- /img/3333.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/3333.png -------------------------------------------------------------------------------- /img/333en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/333en.png -------------------------------------------------------------------------------- /img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/4.png -------------------------------------------------------------------------------- /img/444.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/444.png -------------------------------------------------------------------------------- /img/4444.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/4444.png -------------------------------------------------------------------------------- /img/444en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/444en.png -------------------------------------------------------------------------------- /img/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/5.png -------------------------------------------------------------------------------- /img/555.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/555.png -------------------------------------------------------------------------------- /img/5555.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/5555.png -------------------------------------------------------------------------------- /img/555en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/555en.png -------------------------------------------------------------------------------- /img/666.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/666.png -------------------------------------------------------------------------------- /img/6666.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/6666.png -------------------------------------------------------------------------------- /img/666en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/666en.png -------------------------------------------------------------------------------- /img/777.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/777.png -------------------------------------------------------------------------------- /img/777en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/777en.png -------------------------------------------------------------------------------- /img/888.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/888.png -------------------------------------------------------------------------------- /img/999.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sh3d0ww01f/WaterDragon/b2b2f363b9c8c9c3748058ac3b2f10a026c049cf/img/999.png -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import json 2 | import hashlib 3 | import base64 4 | import time 5 | 6 | global port, clientid 7 | global port, clientid, client_all 8 | import requests 9 | 10 | client_all = {} 11 | port, clientid = [], [] 12 | split_str = "\n|\n-->" 13 | global api, auth_kkey 14 | # ------------------------------------------------------------- 15 | api = "http://xxxxxxxx.xxx.xxxx.xxx:xx" 16 | auth_kkey = "xxxxxxxxx" 17 | token = "ghp_xxxxxxxxxxxxxxxxx" # github_token 18 | # ------------------------------------------------------------ 19 | 20 | CreatNew_name = "WaterDragon" 21 | headers = { 22 | "Authorization": "token " + token, 23 | "Accept": "application/vnd.github.v3+json" 24 | } 25 | BaseInfo = "https://api.github.com/user" 26 | 27 | 28 | # ------------------------------------------------------------nps-------------------------------- 29 | def getkey(): 30 | a = requests.get(url=api + "/auth/gettime").text 31 | time = json.loads(a)["time"] 32 | raw = auth_kkey + str(time) 33 | auth_key = hashlib.md5(raw.encode()).hexdigest() 34 | return auth_key, time 35 | 36 | 37 | def list_tunnel(): 38 | url = api + "/index/gettunnel" 39 | auth_key, time = getkey() 40 | data = { 41 | "auth_key": auth_key, 42 | "timestamp": time, 43 | "offset": 0, 44 | "type": "socks5", 45 | "limit": 10, 46 | "search": "" 47 | } 48 | try: 49 | raw = json.loads(requests.post(url=url, data=data).text) 50 | for item in raw["rows"]: 51 | port.append(item["Port"]) 52 | except: 53 | print("[-] 获取tunnel失败");exit(0) 54 | 55 | 56 | def list_all(): 57 | list_tunnel() 58 | url = api + "/client/list" 59 | auth_key, time = getkey() 60 | data = { 61 | "auth_key": auth_key, 62 | "timestamp": time, 63 | "start": 0, 64 | "limit": 10 65 | } 66 | try: 67 | raw = json.loads(requests.post(url=url, data=data).text) 68 | bridgeport = raw["bridgePort"] 69 | ip = raw["ip"] 70 | id = 0 71 | except: 72 | print("[-] 获取client失败");exit(0) 73 | for item in raw["rows"]: 74 | # print(item) 75 | print("客户端ID:", item["Id"], split_str, "备注:", item["Remark"], split_str, "加密情况:", item["Cnf"]["Crypt"], 76 | split_str, "认证秘钥:", item["VerifyKey"], split_str, "现在是否连接:", item['IsConnect'], split_str, "监听端口:", 77 | port[id], split_str, 78 | "command:./npc -server={0}:{1} -vkey={2} -type=tcp".format(ip, bridgeport, item["VerifyKey"]), 79 | "\n--------------------------") 80 | client_all.update({item["Id"]: {"remark": item["Remark"], "crypt": item["Cnf"]["Crypt"], 81 | "verifykey": item["VerifyKey"], "isconnect": item['IsConnect'], 82 | "command": "command:./npc -server={0}:{1} -vkey={2} -type=tcp".format(ip, 83 | bridgeport, 84 | item[ 85 | "VerifyKey"])}}) 86 | id = id + 1 87 | 88 | 89 | def add_new(OutsidePort, vkey, ifcrypt, remark): 90 | auth_key, time = getkey() 91 | client_data = { 92 | "auth_key": auth_key, 93 | "timestamp": time, 94 | "remark": remark, 95 | "u": "", 96 | "p": "", 97 | "vkey": vkey, 98 | "config_conn_allow": 1, 99 | "compress": 0, 100 | "crypt": ifcrypt 101 | } 102 | resp1 = requests.post(url=api + "/client/add", data=client_data).text 103 | if (json.loads(resp1)["status"] == 1): 104 | url = api + "/client/list" 105 | auth_key, time = getkey() 106 | data = { 107 | "auth_key": auth_key, 108 | "timestamp": time, 109 | "start": 0, 110 | "limit": 10 111 | } 112 | raw = json.loads(requests.post(url=url, data=data).text) 113 | try: 114 | tmp = raw["rows"][-1]["Id"] 115 | except: 116 | print("[-] 添加失败");exit(0) 117 | tunnel_data = { 118 | "auth_key": auth_key, 119 | "timestamp": time, 120 | "type": "socks5", 121 | "client_id": raw["rows"][-1]["Id"], 122 | "remark": "", 123 | "port": OutsidePort, 124 | "target": "", 125 | "local_path": "", 126 | "strip_pre": "", 127 | "password": "" 128 | } 129 | resp2 = requests.post(url=api + "/index/add", data=tunnel_data).text 130 | if json.loads(resp2)["status"] == 1: 131 | print("添加成功!") 132 | else: 133 | print("添加失败,请检查新添加信息是否与已有重复") 134 | delete(raw["rows"][-1]["Id"]) 135 | 136 | 137 | def add(): 138 | OutsidePort = int(input("准备开放的端口:")) 139 | vkey = str(input("通信密钥:")) 140 | ifcrypt = int(input("是否加密(1/0):")) 141 | remark = str(input("备注:")) 142 | add_new(OutsidePort, vkey, ifcrypt, remark) 143 | 144 | 145 | def delete(clientid): 146 | url = api + "/client/del" 147 | auth_key, time = getkey() 148 | client_data = { 149 | "auth_key": auth_key, 150 | "timestamp": time, 151 | "id": clientid 152 | } 153 | resp1 = requests.post(url=api + "/client/del", data=client_data).text 154 | return resp1 155 | 156 | 157 | def ddel(): 158 | clientid = int(input("输入要删除的客户端ID:")) 159 | raw = json.loads(delete(clientid)) 160 | status = raw["status"] 161 | if (status == 1): 162 | print("删除成功") 163 | else: 164 | print(raw["msg"]) 165 | 166 | 167 | def checkc(): 168 | url = api + "/client/list" 169 | auth_key, time = getkey() 170 | data = { 171 | "auth_key": auth_key, 172 | "timestamp": time, 173 | "start": 0, 174 | "limit": 10 175 | } 176 | try: 177 | raw = json.loads(requests.post(url=url, data=data).text) 178 | print("成功连接WebApi") 179 | return 1 180 | except: 181 | print("连接WebApi错误 请检查后再试") 182 | return 0 183 | 184 | 185 | # ---------------------------------------------------------------------------------------------- 186 | # ------------------------------GITHUB_ACTION-------------------------------------------------------- 187 | def base64encode(text): 188 | return base64.b64encode(text).decode() 189 | 190 | 191 | def JudgeIfExist_YML(owner, repo, headers, FileName): 192 | url = f"https://api.github.com/repos/{owner}/{repo}/contents/" + FileName 193 | raw = requests.get(url, headers=headers) 194 | if (raw.status_code == 200): 195 | return json.loads(raw.text)[0]["sha"] 196 | else: 197 | return False 198 | 199 | 200 | def UploadMainYml(owner, repo, headers, command): 201 | Judge = JudgeIfExist_YML(owner, repo, headers, ".github/workflows") 202 | if (Judge): 203 | with open("main.yml", 'r') as f: 204 | MainYml_text = base64encode(f.read().format(command).encode()) 205 | url = f"https://api.github.com/repos/{owner}/{repo}/contents/.github/workflows/main.yml" 206 | data = { 207 | "message": "update", 208 | "content": MainYml_text, 209 | "sha": Judge 210 | } 211 | res = requests.put(url, data=json.dumps(data), headers=headers) 212 | if (res.status_code == 200): 213 | print("[+] Successfully Cover main.yml!") 214 | else: 215 | print("[-] Unknown error") 216 | else: 217 | with open("main.yml", 'r') as f: 218 | MainYml_text = base64encode(f.read().encode()) 219 | url = f"https://api.github.com/repos/{owner}/{repo}/contents/.github/workflows/main.yml" 220 | data = { 221 | "message": "update", 222 | "content": MainYml_text, 223 | } 224 | 225 | res = requests.put(url, data=json.dumps(data), headers=headers) 226 | if (res.status_code == 201): 227 | print("[+] Successfully Upload main.yml!") 228 | else: 229 | print("[-] Unknown error") 230 | 231 | 232 | def CreatNew(CreatNew_name, headers): 233 | data = { 234 | "name": CreatNew_name, 235 | "private": True, 236 | "description": "WaterDragon.Make you flexible like water." 237 | } 238 | a = requests.post("https://api.github.com/user/repos", headers=headers, data=json.dumps(data)) 239 | if (a.status_code == 201): 240 | print("[+] SUCCESSFULLY Creat Cloud repo!") 241 | elif (a.status_code == 422): 242 | print("[-] The name is existed!Please use it or change a NAME") 243 | 244 | 245 | def Use(owner, repo, headers, command): 246 | 247 | onestep = requests.put(f"https://api.github.com/user/starred/{owner}/{repo}", headers=headers) 248 | if (onestep.status_code == 204): 249 | print("[+] Start Success") 250 | requests.delete(f"https://api.github.com/user/starred/{owner}/{repo}", headers=headers) 251 | 252 | 253 | def Enable_workflow(owner, repo, headers): 254 | raw = requests.get(f"https://api.github.com/repos/{owner}/{repo}/actions/workflows", headers=headers) 255 | #print(raw.text) 256 | workflow_id = json.loads(raw.text)["workflows"][0]["id"] 257 | r = requests.put(f"https://api.github.com/repos/{owner}/{repo}/actions/workflows/{workflow_id}/enable", 258 | headers=headers) 259 | data = { 260 | "enabled": True 261 | } 262 | r = requests.put(f"https://api.github.com/repos/{owner}/{repo}/actions/permissions", data=json.dumps(data), 263 | headers=headers) 264 | if (r.status_code == 204): 265 | print(f"[+] Enable workflow_id:{workflow_id}") 266 | else: 267 | print(r.text) 268 | def checkd(BaseInfo, headers): 269 | resp = requests.get(BaseInfo, headers=headers) 270 | if (resp.status_code != 200): 271 | print("[-] Login failed ! :(") 272 | print("[-] Wrong github Access_Token.Plesse get the token: ") 273 | print(" https://github.com/settings/tokens and generate a token for this app") 274 | return 0 275 | else: 276 | return resp 277 | def select(): 278 | list_all() 279 | id = input("输入选择的客户端id:") 280 | return client_all[int(id)]["command"].split('command:')[1] 281 | 282 | 283 | def run_action(username, repo, headers, command): 284 | CreatNew(repo, headers) # Creat 285 | UploadMainYml(username, repo, headers, command) 286 | time.sleep(1) 287 | Enable_workflow(username, repo, headers) 288 | Use(username, repo, headers, command) 289 | 290 | 291 | def stop(username, repo, headers): 292 | order = 0 293 | id_list = [] 294 | raw = requests.get(f"https://api.github.com/repos/{username}/{repo}/actions/workflows", headers=headers) 295 | workflow_id = json.loads(raw.text)["workflows"][0]["id"] 296 | raw = requests.get(f"https://api.github.com/repos/{username}/{repo}/actions/workflows/{workflow_id}/runs", 297 | headers=headers).text 298 | for item in json.loads(raw)["workflow_runs"][:10]: # item["workflow_id"], 299 | print(order, ") id:", item["id"], "\n|目前状态:", item["status"], "\n|起始时间", item["run_started_at"]) 300 | id_list.append(item["id"]) 301 | order = order + 1 302 | choose = input("请输入要取消运行的ID前的序号:") 303 | resp = requests.post(f"https://api.github.com/repos/{username}/{repo}/actions/runs/{id_list[int(choose)]}/cancel", 304 | headers=headers).status_code 305 | if (resp == 202): 306 | print("取消运行成功") 307 | 308 | 309 | # --------------------------------------------------------------------------------------------------- 310 | 311 | 312 | current = "menu" 313 | s = string = """ 314 | [+] 输入 socks5 进入socks5隧道管理(增、减、查看) 315 | [+] 输入 manager 进入Github机器管理 316 | [+] 输入 back 回退 317 | [+] 输入 help 获取帮助 318 | """ 319 | print(s) 320 | while True: 321 | text = input(current + ">") 322 | if (current == "menu" and text == "help"): 323 | print(string) 324 | elif (current == "socks5" and text == "help"): 325 | print(""" 326 | [+] 输入 add 增加socks5隧道 327 | [+] 输入 del 删除已有socks5隧道 328 | [+] 输入 list 列出现存socks5隧道 329 | """) 330 | elif (current == "manager" and text == "help"): 331 | print(""" 332 | [+] 输入 select 选择已有socks5 并获取连接 333 | [+] 输入 stop 取消运行现隧道 334 | """) 335 | if (text == "socks5"): 336 | current = "socks5" 337 | if not checkc(): 338 | current = "menu" 339 | elif (text == "manager"): 340 | current = "manager" 341 | resp = checkd(BaseInfo, headers) 342 | if (not resp): 343 | current = "menu" 344 | exit(0) 345 | response_raw = resp.text 346 | response = json.loads(response_raw) 347 | username = response["login"] 348 | repo_all = response["repos_url"] 349 | print("[+] Login successfully ! Welcome :)" + username) 350 | elif (text == "back"): 351 | current = "menu" 352 | if (current == "socks5"): 353 | if (text == "list"): 354 | list_all() 355 | elif (text == "add"): 356 | add() 357 | elif (text == "del"): 358 | ddel() 359 | if (current == "manager"): 360 | if (text == "select"): 361 | command = select() 362 | run_action(username, CreatNew_name, headers, command) 363 | if (text == "stop"): 364 | stop(username, CreatNew_name, headers) 365 | -------------------------------------------------------------------------------- /main.yml: -------------------------------------------------------------------------------- 1 | name: 'GetShell' 2 | 3 | on: 4 | watch: 5 | types: started 6 | jobs: 7 | bot: 8 | 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@master 14 | - name: EXECUTE 15 | 16 | run: | 17 | wget https://github.com/ehang-io/nps/releases/download/v0.26.10/linux_amd64_client.tar.gz 18 | tar -axvf linux_amd64_client.tar.gz 19 | {} -------------------------------------------------------------------------------- /main_En.py: -------------------------------------------------------------------------------- 1 | import json 2 | import hashlib 3 | import base64 4 | import time 5 | 6 | global port, clientid 7 | global port, clientid, client_all 8 | import requests 9 | 10 | client_all = {} 11 | port, clientid = [], [] 12 | split_str = "\n|\n-->" 13 | global api, auth_kkey 14 | # ------------------------------------------------------------- 15 | api = "http://xxxxxxxx.xxx.xxxx.xxx:xx" 16 | auth_kkey = "xxxxxxxxx" 17 | token = "ghp_xxxxxxxxxxxxxxxxx" # github_token 18 | # ------------------------------------------------------------ 19 | 20 | CreatNew_name = "WaterDragon" 21 | headers = { 22 | "Authorization": "token " + token, 23 | "Accept": "application/vnd.github.v3+json" 24 | } 25 | BaseInfo = "https://api.github.com/user" 26 | 27 | 28 | # ------------------------------------------------------------nps-------------------------------- 29 | def getkey(): 30 | a = requests.get(url=api + "/auth/gettime").text 31 | time = json.loads(a)["time"] 32 | raw = auth_kkey + str(time) 33 | auth_key = hashlib.md5(raw.encode()).hexdigest() 34 | return auth_key, time 35 | 36 | 37 | def list_tunnel(): 38 | url = api + "/index/gettunnel" 39 | auth_key, time = getkey() 40 | data = { 41 | "auth_key": auth_key, 42 | "timestamp": time, 43 | "offset": 0, 44 | "type": "socks5", 45 | "limit": 10, 46 | "search": "" 47 | } 48 | raw = json.loads(requests.post(url=url, data=data).text) 49 | for item in raw["rows"]: 50 | port.append(item["Port"]) 51 | 52 | 53 | def list_all(): 54 | list_tunnel() 55 | url = api + "/client/list" 56 | auth_key, time = getkey() 57 | data = { 58 | "auth_key": auth_key, 59 | "timestamp": time, 60 | "start": 0, 61 | "limit": 10 62 | } 63 | raw = json.loads(requests.post(url=url, data=data).text) 64 | bridgeport = raw["bridgePort"] 65 | ip = raw["ip"] 66 | id = 0 67 | for item in raw["rows"]: 68 | # print(item) 69 | print("ClientID:", item["Id"], split_str, "Remark:", item["Remark"], split_str, "Ifcrypto:", item["Cnf"]["Crypt"], 70 | split_str, "Verifykey:", item["VerifyKey"], split_str, "Ifconnect:", item['IsConnect'], split_str, "ListenPort:", 71 | port[id], split_str, 72 | "command:./npc -server={0}:{1} -vkey={2} -type=tcp".format(ip, bridgeport, item["VerifyKey"]), 73 | "\n--------------------------") 74 | client_all.update({item["Id"]: {"remark": item["Remark"], "crypt": item["Cnf"]["Crypt"], 75 | "verifykey": item["VerifyKey"], "isconnect": item['IsConnect'], 76 | "command": "command:./npc -server={0}:{1} -vkey={2} -type=tcp".format(ip, 77 | bridgeport, 78 | item[ 79 | "VerifyKey"])}}) 80 | id = id + 1 81 | 82 | 83 | def add_new(OutsidePort, vkey, ifcrypt, remark): 84 | auth_key, time = getkey() 85 | client_data = { 86 | "auth_key": auth_key, 87 | "timestamp": time, 88 | "remark": remark, 89 | "u": "", 90 | "p": "", 91 | "vkey": vkey, 92 | "config_conn_allow": 1, 93 | "compress": 0, 94 | "crypt": ifcrypt 95 | } 96 | resp1 = requests.post(url=api + "/client/add", data=client_data).text 97 | if (json.loads(resp1)["status"] == 1): 98 | url = api + "/client/list" 99 | auth_key, time = getkey() 100 | data = { 101 | "auth_key": auth_key, 102 | "timestamp": time, 103 | "start": 0, 104 | "limit": 10 105 | } 106 | raw = json.loads(requests.post(url=url, data=data).text) 107 | 108 | tunnel_data = { 109 | "auth_key": auth_key, 110 | "timestamp": time, 111 | "type": "socks5", 112 | "client_id": raw["rows"][-1]["Id"], 113 | "remark": "", 114 | "port": OutsidePort, 115 | "target": "", 116 | "local_path": "", 117 | "strip_pre": "", 118 | "password": "" 119 | } 120 | resp2 = requests.post(url=api + "/index/add", data=tunnel_data).text 121 | if json.loads(resp2)["status"] == 1: 122 | print("add successfully!") 123 | else: 124 | print("Wrong:failed to add,please check if the information repeat!") 125 | delete(raw["rows"][-1]["Id"]) 126 | 127 | 128 | def add(): 129 | OutsidePort = int(input("ListenPort:")) 130 | vkey = str(input("key:")) 131 | ifcrypt = int(input("Ifcrypt(1/0):")) 132 | remark = str(input("Remark:")) 133 | add_new(OutsidePort, vkey, ifcrypt, remark) 134 | 135 | 136 | def delete(clientid): 137 | url = api + "/client/del" 138 | auth_key, time = getkey() 139 | client_data = { 140 | "auth_key": auth_key, 141 | "timestamp": time, 142 | "id": clientid 143 | } 144 | resp1 = requests.post(url=api + "/client/del", data=client_data).text 145 | return resp1 146 | 147 | 148 | def ddel(): 149 | clientid = int(input("Choose the client ID that you want to del:")) 150 | raw = json.loads(delete(clientid)) 151 | status = raw["status"] 152 | if (status == 1): 153 | print("Delete successfully") 154 | else: 155 | print(raw["msg"]) 156 | 157 | 158 | def checkc(): 159 | url = api + "/client/list" 160 | auth_key, time = getkey() 161 | data = { 162 | "auth_key": auth_key, 163 | "timestamp": time, 164 | "start": 0, 165 | "limit": 10 166 | } 167 | try: 168 | raw = json.loads(requests.post(url=url, data=data).text) 169 | print("[+] Connect WebApi successfully") 170 | return 1 171 | except: 172 | print("[-] Wrong : Connect WebApi ,Retry please") 173 | return 0 174 | 175 | 176 | # ---------------------------------------------------------------------------------------------- 177 | # ------------------------------GITHUB_ACTION-------------------------------------------------------- 178 | def base64encode(text): 179 | return base64.b64encode(text).decode() 180 | 181 | 182 | def JudgeIfExist_YML(owner, repo, headers, FileName): 183 | url = f"https://api.github.com/repos/{owner}/{repo}/contents/" + FileName 184 | raw = requests.get(url, headers=headers) 185 | if (raw.status_code == 200): 186 | return json.loads(raw.text)[0]["sha"] 187 | else: 188 | return False 189 | 190 | 191 | def UploadMainYml(owner, repo, headers, command): 192 | Judge = JudgeIfExist_YML(owner, repo, headers, ".github/workflows") 193 | if (Judge): 194 | with open("main.yml", 'r') as f: 195 | MainYml_text = base64encode(f.read().format(command).encode()) 196 | url = f"https://api.github.com/repos/{owner}/{repo}/contents/.github/workflows/main.yml" 197 | data = { 198 | "message": "update", 199 | "content": MainYml_text, 200 | "sha": Judge 201 | } 202 | res = requests.put(url, data=json.dumps(data), headers=headers) 203 | if (res.status_code == 200): 204 | print("[+] Successfully Cover main.yml!") 205 | else: 206 | print("[-] Unknown error") 207 | else: 208 | with open("main.yml", 'r') as f: 209 | MainYml_text = base64encode(f.read().encode()) 210 | url = f"https://api.github.com/repos/{owner}/{repo}/contents/.github/workflows/main.yml" 211 | data = { 212 | "message": "update", 213 | "content": MainYml_text, 214 | } 215 | 216 | res = requests.put(url, data=json.dumps(data), headers=headers) 217 | if (res.status_code == 201): 218 | print("[+] Successfully Upload main.yml!") 219 | else: 220 | print("[-] Unknown error") 221 | 222 | 223 | def CreatNew(CreatNew_name, headers): 224 | data = { 225 | "name": CreatNew_name, 226 | "private": True, 227 | "description": "WaterDragon.Make you flexible like water." 228 | } 229 | a = requests.post("https://api.github.com/user/repos", headers=headers, data=json.dumps(data)) 230 | if (a.status_code == 201): 231 | print("[+] SUCCESSFULLY Creat Cloud repo!") 232 | elif (a.status_code == 422): 233 | print("[-] The name is existed!Please use it or change a NAME") 234 | 235 | 236 | def Use(owner, repo, headers, command): 237 | 238 | onestep = requests.put(f"https://api.github.com/user/starred/{owner}/{repo}", headers=headers) 239 | if (onestep.status_code == 204): 240 | print("[+] Start Success") 241 | requests.delete(f"https://api.github.com/user/starred/{owner}/{repo}", headers=headers) 242 | 243 | 244 | def Enable_workflow(owner, repo, headers): 245 | raw = requests.get(f"https://api.github.com/repos/{owner}/{repo}/actions/workflows", headers=headers) 246 | #print(raw.text) 247 | workflow_id = json.loads(raw.text)["workflows"][0]["id"] 248 | r = requests.put(f"https://api.github.com/repos/{owner}/{repo}/actions/workflows/{workflow_id}/enable", 249 | headers=headers) 250 | data = { 251 | "enabled": True 252 | } 253 | r = requests.put(f"https://api.github.com/repos/{owner}/{repo}/actions/permissions", data=json.dumps(data), 254 | headers=headers) 255 | if (r.status_code == 204): 256 | print(f"[+] Enable workflow_id:{workflow_id}") 257 | else: 258 | print(r.text) 259 | 260 | 261 | def checkd(BaseInfo, headers): 262 | resp = requests.get(BaseInfo, headers=headers) 263 | if (resp.status_code != 200): 264 | print("[-] Login failed ! :(") 265 | print("[-] Wrong github Access_Token.Plesse get the token: ") 266 | print(" https://github.com/settings/tokens and generate a token for this app") 267 | return 0 268 | else: 269 | return resp 270 | 271 | 272 | def select(): 273 | list_all() 274 | id = input("choose a id that you want to choose of a socks5 client:") 275 | return client_all[int(id)]["command"].split('command:')[1] 276 | 277 | 278 | def run_action(username, repo, headers, command): 279 | CreatNew(repo, headers) # Creat 280 | UploadMainYml(username, repo, headers, command) 281 | time.sleep(1) 282 | Enable_workflow(username, repo, headers) 283 | Use(username, repo, headers, command) 284 | 285 | 286 | def stop(username, repo, headers): 287 | order = 0 288 | id_list = [] 289 | raw = requests.get(f"https://api.github.com/repos/{username}/{repo}/actions/workflows", headers=headers) 290 | workflow_id = json.loads(raw.text)["workflows"][0]["id"] 291 | raw = requests.get(f"https://api.github.com/repos/{username}/{repo}/actions/workflows/{workflow_id}/runs", 292 | headers=headers).text 293 | for item in json.loads(raw)["workflow_runs"][:10]: # item["workflow_id"], 294 | print(order, ") id:", item["id"], "\n|目前状态:", item["status"], "\n|起始时间", item["run_started_at"]) 295 | id_list.append(item["id"]) 296 | order = order + 1 297 | choose = input("Press the ID you want to stop:") 298 | resp = requests.post(f"https://api.github.com/repos/{username}/{repo}/actions/runs/{id_list[int(choose)]}/cancel", 299 | headers=headers).status_code 300 | if (resp == 202): 301 | print("stop process successfully") 302 | 303 | 304 | # --------------------------------------------------------------------------------------------------- 305 | 306 | 307 | current = "menu" 308 | s = string = """ 309 | [+] press socks5 to enter socks5 manager(add、del、list) 310 | [+] press manager to enter GithubAction process manager 311 | [+] press back to back to menu 312 | [+] press help to get HELP information 313 | """ 314 | print(s) 315 | while True: 316 | text = input(current + ">") 317 | if (current == "menu" and text == "help"): 318 | print(string) 319 | elif (current == "socks5" and text == "help"): 320 | print(""" 321 | [+] press add to add socks5 client 322 | [+] press del to delete socks5 client 323 | [+] press list to list all socks5 client 324 | """) 325 | elif (current == "manager" and text == "help"): 326 | print(""" 327 | [+] press select to select a socks5 client and connect 328 | [+] press stop to cancel a GithubAction process 329 | """) 330 | if (text == "socks5"): 331 | current = "socks5" 332 | if not checkc(): 333 | current = "menu" 334 | elif (text == "manager"): 335 | current = "manager" 336 | resp = checkd(BaseInfo, headers) 337 | if (not resp): 338 | current = "menu" 339 | exit(0) 340 | response_raw = resp.text 341 | response = json.loads(response_raw) 342 | username = response["login"] 343 | repo_all = response["repos_url"] 344 | print("[+] Login successfully ! Welcome :)" + username) 345 | elif (text == "back"): 346 | current = "menu" 347 | if (current == "socks5"): 348 | if (text == "list"): 349 | list_all() 350 | elif (text == "add"): 351 | add() 352 | elif (text == "del"): 353 | ddel() 354 | if (current == "manager"): 355 | if (text == "select"): 356 | command = select() 357 | run_action(username, CreatNew_name, headers, command) 358 | if (text == "stop"): 359 | stop(username, CreatNew_name, headers) --------------------------------------------------------------------------------