t880216t-server 1.5.20

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 (104) hide show
  1. package/LICENSE +124 -0
  2. package/README.md +191 -0
  3. package/bin/nohost.js +178 -0
  4. package/bin/plugin.js +70 -0
  5. package/bin/util.js +93 -0
  6. package/index.js +89 -0
  7. package/lib/config.js +42 -0
  8. package/lib/index.js +205 -0
  9. package/lib/main/cgi/getSettings.js +11 -0
  10. package/lib/main/cgi/getVersion.js +12 -0
  11. package/lib/main/cgi/login.js +14 -0
  12. package/lib/main/cgi/restart.js +5 -0
  13. package/lib/main/cgi/setAdmin.js +6 -0
  14. package/lib/main/cgi/setDomain.js +13 -0
  15. package/lib/main/cgi/status.js +122 -0
  16. package/lib/main/index.js +94 -0
  17. package/lib/main/router.js +79 -0
  18. package/lib/main/storage.js +132 -0
  19. package/lib/main/util.js +138 -0
  20. package/lib/main/whistleMgr.js +56 -0
  21. package/lib/main/worker.js +52 -0
  22. package/lib/main/workerNum.js +11 -0
  23. package/lib/plugins/account/whistle.share/menu.html +171 -0
  24. package/lib/plugins/account/whistle.share/package.json +20 -0
  25. package/lib/plugins/account/whistle.storage/index.js +43 -0
  26. package/lib/plugins/account/whistle.storage/package.json +8 -0
  27. package/lib/plugins/account/whistle.storage/rules.txt +1 -0
  28. package/lib/plugins/whistle.nohost/_rules.txt +38 -0
  29. package/lib/plugins/whistle.nohost/index.js +3 -0
  30. package/lib/plugins/whistle.nohost/initial.js +9 -0
  31. package/lib/plugins/whistle.nohost/lib/accountMgr.js +750 -0
  32. package/lib/plugins/whistle.nohost/lib/envMgr.js +114 -0
  33. package/lib/plugins/whistle.nohost/lib/rulesServer.js +85 -0
  34. package/lib/plugins/whistle.nohost/lib/tunnelRulesServer.js +71 -0
  35. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/account/changePassword.js +8 -0
  36. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/activeAccount.js +9 -0
  37. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/addAccount.js +8 -0
  38. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/allAccounts.js +9 -0
  39. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/changeNotice.js +8 -0
  40. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/changePassword.js +8 -0
  41. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/enableGuest.js +5 -0
  42. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/getAuthKey.js +3 -0
  43. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/getSettings.js +22 -0
  44. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/login.js +14 -0
  45. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/move.js +9 -0
  46. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/removeAccount.js +9 -0
  47. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/setAccountRules.js +5 -0
  48. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/setAuthKey.js +5 -0
  49. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/setDefaultRules.js +5 -0
  50. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/setEntryPatterns.js +6 -0
  51. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/setJsonData.js +5 -0
  52. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/setRulesTpl.js +5 -0
  53. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/setTestRules.js +5 -0
  54. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/admin/specPattern.js +4 -0
  55. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/allowlist.js +4 -0
  56. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/entryRules.js +4 -0
  57. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/follow.js +17 -0
  58. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/getEnv.js +12 -0
  59. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/list.js +43 -0
  60. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/patterns.js +14 -0
  61. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/pluginRules.js +61 -0
  62. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/proxy.js +42 -0
  63. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/proxyNetwork.js +12 -0
  64. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/redirect.js +10 -0
  65. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/selectEnv.js +30 -0
  66. package/lib/plugins/whistle.nohost/lib/uiServer/cgi/unfollow.js +4 -0
  67. package/lib/plugins/whistle.nohost/lib/uiServer/index.js +60 -0
  68. package/lib/plugins/whistle.nohost/lib/uiServer/network.js +38 -0
  69. package/lib/plugins/whistle.nohost/lib/uiServer/openAPI.js +94 -0
  70. package/lib/plugins/whistle.nohost/lib/uiServer/router.js +85 -0
  71. package/lib/plugins/whistle.nohost/lib/util.js +230 -0
  72. package/lib/plugins/whistle.nohost/lib/whistle.js +149 -0
  73. package/lib/plugins/whistle.nohost/lib/whistleMgr.js +94 -0
  74. package/lib/plugins/whistle.nohost/package.json +7 -0
  75. package/lib/plugins/whistle.nohost/rules.txt +3 -0
  76. package/lib/service/cgi/export.js +76 -0
  77. package/lib/service/cgi/import.js +33 -0
  78. package/lib/service/cgi/util.js +35 -0
  79. package/lib/service/index.js +37 -0
  80. package/lib/service/router.js +7 -0
  81. package/lib/service/server.js +25 -0
  82. package/lib/util/address.js +55 -0
  83. package/lib/util/getPort.js +19 -0
  84. package/lib/util/login.js +55 -0
  85. package/lib/util/parseDomain.js +17 -0
  86. package/lib/whistle.js +86 -0
  87. package/package.json +135 -0
  88. package/pnpm-workspace.yaml +6 -0
  89. package/public/admin.75d42731d4aa7f7a558d3abf2a375fcb.js +2 -0
  90. package/public/admin.75d42731d4aa7f7a558d3abf2a375fcb.js.LICENSE.txt +76 -0
  91. package/public/admin.html +11 -0
  92. package/public/button.js +2 -0
  93. package/public/button.js.LICENSE.txt +31 -0
  94. package/public/capture.7bab900f27c9bb1b0e33523e994554ae.js +2 -0
  95. package/public/capture.7bab900f27c9bb1b0e33523e994554ae.js.LICENSE.txt +83 -0
  96. package/public/capture.html +11 -0
  97. package/public/eed368d0656f03932671530c3132ed61.svg +1 -0
  98. package/public/favicon.ico +0 -0
  99. package/public/network.e4814ec8c966a8a789296679619ec573.js +2 -0
  100. package/public/network.e4814ec8c966a8a789296679619ec573.js.LICENSE.txt +76 -0
  101. package/public/network.html +11 -0
  102. package/public/select.cb638be6656d02a558f2690acd59901a.js +2 -0
  103. package/public/select.cb638be6656d02a558f2690acd59901a.js.LICENSE.txt +24 -0
  104. package/public/select.html +26 -0
package/LICENSE ADDED
@@ -0,0 +1,124 @@
1
+ Tencent is pleased to support the open source community by making nohost-环境配置与抓包调试平台 available.
2
+
3
+ Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. The below software in this distribution may have been modified by THL A29 Limited ("Tencent Modifications"). All Tencent Modifications are Copyright (C) THL A29 Limited.
4
+
5
+ nohost-环境配置与抓包调试平台 is licensed under the MIT License except for the third-party components listed below.
6
+
7
+
8
+ Terms of the MIT License:
9
+ ---------------------------------------------------
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15
+
16
+
17
+
18
+ Other dependencies and licenses:
19
+
20
+
21
+
22
+ Open Source Software Licensed under the ISC License:
23
+ --------------------------------------------------------------------
24
+ 1. lru-cache
25
+
26
+
27
+ Terms of the ISC License:
28
+ ---------------------------------------------------
29
+ Permission to use, copy, modify, and/or distribute this software for any
30
+ purpose with or without fee is hereby granted, provided that the above
31
+ copyright notice and this permission notice appear in all copies.
32
+
33
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
34
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
35
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
36
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
37
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
38
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
39
+ IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
40
+
41
+
42
+
43
+ Open Source Software Licensed under the MIT License:
44
+ --------------------------------------------------------------------
45
+ 1. whistle
46
+ Copyright (c) 2015 avwo
47
+
48
+ 2. async-limiter
49
+ Copyright (c) 2017 Samuel Reed <samuel.trace.reed@gmail.com>
50
+
51
+ 3. basic-auth
52
+ Copyright (c) 2013 TJ Holowaychuk
53
+ Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
54
+ Copyright (c) 2015-2016 Douglas Christopher Wilson <doug@somethingdoug.com>"
55
+
56
+ 4. colors
57
+ Copyright (c) Marak Squires
58
+ Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)"
59
+
60
+ 5. cookie
61
+ Copyright (c) 2012-2014 Roman Shtylman <shtylman@gmail.com>
62
+ Copyright (c) 2015 Douglas Christopher Wilson <doug@somethingdoug.com>"
63
+
64
+ 6. crc32
65
+ Copyright (C) <2011> by <Jameson Little>
66
+
67
+ 7. fs-extra
68
+ Copyright (c) 2011-2017 JP Richardson
69
+
70
+ 8. hagent
71
+ Copyright (c) 2017 avenwu
72
+
73
+ 9. hparser
74
+ Copyright (c) 2017 avenwu
75
+
76
+ 10. koa
77
+ Copyright (c) 2019 Koa contributors
78
+
79
+ 11. koa-bodyparser
80
+ Copyright (c) 2014 dead_horse
81
+
82
+ 12. koa-compress
83
+ Copyright (c) 2014 Jonathan Ong me@jongleberry.com
84
+
85
+ 13. koa-onerror
86
+ Copyright (c) 2014 node_modules.
87
+ Copyright (c) 2015 - present koajs and other contributors.
88
+
89
+ 14. koa-router
90
+ Copyright (c) 2015 Alexander C. Mingoia
91
+
92
+ 15. koa-static
93
+ Copyright (c) 2019 Koa Static Contributors
94
+
95
+ 16. lodash.get
96
+ Copyright 2012-2016 The Dojo Foundation <http://dojofoundation.org/>
97
+ Based on Underscore.js, copyright 2009-2016 Jeremy Ashkenas,
98
+ DocumentCloud and Investigative Reporters & Editors <http://underscorejs.org/>"
99
+
100
+ 17. parseurl
101
+ Copyright (c) 2014 Jonathan Ong <me@jongleberry.com>
102
+ Copyright (c) 2014-2017 Douglas Christopher Wilson <doug@somethingdoug.com>"
103
+
104
+ 18. pfork
105
+ Copyright (c) 2016 avenwu
106
+
107
+ 19. simpleproto
108
+ Copyright (c) 2018 avenwu
109
+
110
+ 20. socketx
111
+ Copyright (c) 2018 avenwu
112
+
113
+ 21. starting
114
+ Copyright (c) 2015 avwo
115
+
116
+
117
+ Terms of the MIT License:
118
+ ---------------------------------------------------
119
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
120
+
121
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
122
+
123
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
124
+
package/README.md ADDED
@@ -0,0 +1,191 @@
1
+ # Nohost
2
+ [![NPM version](https://img.shields.io/npm/v/t880216t-server.svg?style=flat-square)](https://npmjs.org/package/t880216t-server)
3
+ [![node version](https://img.shields.io/badge/node.js-%3E=_8.0.0-green.svg?style=flat-square)](http://nodejs.org/download/)
4
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/Tencent/nohost/pulls)
5
+ [![License](https://img.shields.io/npm/l/t880216t-server.svg?style=flat-square)](https://www.npmjs.com/package/t880216t-server)
6
+
7
+ Nohost 是基于 [Whistle](https://github.com/avwo/whistle) 实现的多用户多环境配置及抓包调试系统,不仅具备 Whistle 的所有功能,并在 Whistle 基础上扩展了一些功能,且支持多人多环境同时使用,主要用于部署在公共服务器上供整个部门(公司)的同事共同使用,具有以下功能:
8
+ 1. 环境共享:前端无需配后台环境,后台无需配前端环境,其他人无需配任何环境
9
+ 2. 抓包调试:远程实时抓包调试,支持各种 Whistle 规则,以及通过链接分享抓包数据
10
+ 3. 历史记录:可以把环境配置及抓包数据沉淀下来,供后续随时切换查看
11
+ 4. 插件扩展:可以通过插件扩展实现诸如 [inspect](https://github.com/whistle-plugins/whistle.inspect),[vase](https://github.com/whistle-plugins/whistle.vase),[autosave](https://github.com/whistle-plugins/whistle.autosave) 等功能
12
+ 5. 对外接口:提供对外接口,可供发布系统、CI等工具操作,实现自动化增删查改环境配置
13
+
14
+ ![效果图](https://user-images.githubusercontent.com/11450939/40436253-28a90f28-5ee5-11e8-97a5-fd598e32e0df.gif)
15
+
16
+ # 目录
17
+ [一. 准备](#prepare)
18
+
19
+ [二. 安装](#install)
20
+
21
+ [三. 设置](#settings)
22
+
23
+ [四. 访问](#access)
24
+
25
+ [五. 账号](#accounts)
26
+
27
+ [六. 配置](#config)
28
+
29
+ [七. 规则](#Whistle)
30
+
31
+ [八. 开发](#development)
32
+
33
+ [九. 加群](#add)
34
+
35
+
36
+ ## <a href="#prepare" id="prepare">一. 准备</a>
37
+ 安装 Nohost 之前,建议先做好以下工作:
38
+
39
+ 1. 准备一台服务器,假设IP为:10.1.2.3(以你自己的服务器为准,建议4核8G以上的配置)
40
+ 2. 准备一个域名(以下假设为:nohost.imweb.io),并把 DNS 指向上述服务器(10.1.2.3)
41
+ 3. 收集涉及域名的证书对,只支持 `xxx.key` 和 `xxx.crt`(非必须,但建议用正式的证书,否则要么 Nohost 里面无法查看 HTTPS 的内容,要么每个访问 Nohost 的客户端都要安装一遍根证书)
42
+
43
+ > 申请域名的好处是可以直接用域名访问管理及账号页面,手机也可以通过域名设置代理访问 Nohost,方便记忆及输入
44
+
45
+ ## <a href="#install" id="install">二. 安装</a>
46
+ 首先,需要安装Node(建议使用最新的LTS版本):[Node](https://nodejs.org/en/)
47
+
48
+ Node安装成功后,通过npm安装 `nohost`:
49
+ ``` sh
50
+ npm i -g t880216t-server --registry=https://r.npm.taobao.org
51
+ ```
52
+ 安装完成后执行启动命令:
53
+ ``` sh
54
+ n2 start
55
+ ```
56
+ > 也可以启动时直接设置当前 Nohost 服务到域名 `n2 restart -o nohost.imweb.io`
57
+ > Nohost 的默认端口为 8080,如果需要自定义端口,可以通过 `n2 restart -p 80` 设置。
58
+ > 如果命令行提示没有对应命令,检查下系统环境变量 `PATH` 配置,看看 Nohost 安装后生成的命令所在目录是否已添加到 `PATH`。
59
+
60
+ 重启 `Nohost`:
61
+ ``` sh
62
+ n2 restart
63
+ ```
64
+
65
+ 停止 `Nohost`:
66
+ ``` sh
67
+ n2 stop
68
+ ```
69
+
70
+ 重置管理员账号:
71
+ ``` sh
72
+ n2 restart --reset
73
+ ```
74
+
75
+ ## <a href="#settings" id="settings">三. 设置</a>
76
+ 安装启动成功后,打开管理员页面 `http://10.1.2.3:8080/admin.html#system/administrator`,输入默认用户名(`admin`)和密码(`123456`),打开系统配置后:
77
+ > 其中 `10.1.2.3` 表示Nohost运行的服务器IP,具体根据实际 ServerIP 替换
78
+ 1. 修改管理员的默认账号名和密码(**不建议使用默认账号及密码,如果忘记管理员账号名或密码,可以通过 `n2 restart --reset` 重置**)
79
+ 2. 设置Nohost的域名(将申请的域名填上,如果需要设置多个域名,可以通过逗号 `,` 分隔,也可以通过启动参数 `-o www.xxx.com,www.yyy.com` 设置)
80
+ 3. 上传涉及的 key 和证书(证书只支持 `.crt` 格式)
81
+
82
+ ![admin](https://user-images.githubusercontent.com/11450939/69247822-0c010b00-0be6-11ea-8b03-5a0ae4b12c6e.gif)
83
+
84
+ **Note: 设置的域名 DNS 一定要指向该IP,否则可能出现不可用状态,上述配置会自动重启服务,建议避免频繁操作**
85
+
86
+ ## <a href="#access" id="access">四. 访问</a>
87
+ Nohost 本身就是一个代理,可以直接配置浏览器或系统代理访问,也可以通过 Nginx反向代理访问,为方便大家使用,针对不同的人群可以使用不同的方案(以下用 `nohost.imweb.io` 表示 Nohost 的域名,具体域名需要自己申请及设置)。
88
+
89
+ #### 前端开发
90
+ 前端开发建议使用最新版的 [Whistle](https://github.com/avwo/whistle),可以通过以下两种方式访问 Nohost:
91
+
92
+ 1. 直接在 Whistle 上配置远程规则
93
+ ``` txt
94
+ @http://nohost.imweb.io:8080/whistle.nohost/cgi-bin/plugin-rules
95
+ ```
96
+ > 上述配置表示 Whistle 从 `http://nohost.imweb.io:8080/whistle.nohost/cgi-bin/plugin-rules` 获取 Nohost 的生成的入口规则,并且如果 Nohost 规则有变会自动更新规则,这些规则是由 Nohost 上传证书的域名及界面 `配置/入口配置` 配置的规则自动生成(具体参见后面的**配置**),这些规则可以自动过滤掉无关请求,只会把相关的请求转到Nohost。
97
+
98
+ 当然这种直接手动配置在 Whistle 上还不是最好的方式,更建议的方式是把这些规则集成到插件里面,这样开发者只需安装插件即可。
99
+ 2. **【强烈推荐】** 集成 Whistle 插件,具体参考:[https://github.com/nohosts/whistle.nohost-imweb/blob/master/dev.md](https://github.com/nohosts/whistle.nohost-imweb/blob/master/dev.md)
100
+
101
+ #### 后台开发
102
+ 后台开发推荐使用 Chrome 的 [SwitchyOmega](https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif) 配置代理规则 (如上述代理配置 `nohost.imweb.io` + `8080`),如果不想所有请求都转到 Nohost,可以配置 SwitchyOmega 的自动切换或者用PAC脚本代替,也可以参考 `nohost-client` 打包一个客户端:[https://github.com/nohosts/client](https://github.com/nohosts/client)。手机端可以直接配代理,或者通过 VPN App 设置代理,如 iPhone 可以用 `detour`。
103
+
104
+ #### 其他人员
105
+ 非开发人员尽量使用客户端、APP、或通过外网转发的方式,减少他们的接入成本,如何打包客户端参考:[https://github.com/nohosts/client](https://github.com/nohosts/client);手机等同后台开发的配置方式。
106
+
107
+ #### 外网访问
108
+ 一般 Nohost 是部署在公司内网,外网是不可以直接访问,需要通过接入层(如:Nginx)转发。
109
+
110
+ ## <a href="#accounts" id="accounts">五. 账号</a>
111
+ 安装好插件或配置好代理后,打开相关页面(这些页面的域名必须在上面上传证书里面,如果没有需要额外配置,具体参考下方 **配置** 说明),即可看到页面左下脚出现一个小圆点,点击小圆点可以进行切换环境:
112
+
113
+ ![证书列表](https://user-images.githubusercontent.com/29788452/104725825-9652e980-576d-11eb-980c-69cdade67da4.png)
114
+
115
+ ![Whistle插件列表](https://user-images.githubusercontent.com/11450939/69324924-4ae59e00-0c84-11ea-994c-7c3914257470.png)
116
+
117
+ ![打开页面](https://user-images.githubusercontent.com/11450939/69325133-9b5cfb80-0c84-11ea-8213-8c64d5365538.png)
118
+
119
+ ![点击按钮](https://user-images.githubusercontent.com/11450939/69325935-ecb9ba80-0c85-11ea-8cca-3c73bee69fd6.png)
120
+
121
+ > 如果页面左下脚没出现小圆点,可以看下面 **配置** 说明
122
+ 第一次打开小圆点只有一个 **无代理环境**,需要管理员添加账号:
123
+ ![添加账号](https://user-images.githubusercontent.com/29788452/104725989-d9ad5800-576d-11eb-9d25-34e06d0bb41e.png)
124
+
125
+ 添加完账号后,打开独立的环境选择页面 `http://nohost.imweb.io:8080`:
126
+
127
+ ![选择环境页面](https://user-images.githubusercontent.com/29788452/104726057-f34e9f80-576d-11eb-9ec2-c429887f354d.png)
128
+ ![个人账号页面](https://user-images.githubusercontent.com/11450939/69358193-6fac3680-0cc1-11ea-9406-0f036d888d7c.png)
129
+ ![image](https://user-images.githubusercontent.com/11450939/69358459-d92c4500-0cc1-11ea-8263-08bb216fc357.png)
130
+
131
+ 创建完环境后,可以在环境里面配置任何 Whistle 规则,跟普通到本地 Whistle 功能一模一样,甚至更多。每个实例可以建立上百个账号,每个账号可以建立上百个环境,具体取决于你到机器性能。
132
+
133
+ ## <a href="#config" id="config">六. 配置</a>
134
+ 默认情况下,只有证书里面域名的请求才会被转发到各个账号,且 html 类型的内容会自动注入小圆点,但在实际应用中你可能会遇到以下问题:
135
+
136
+ #### 域名证书问题
137
+ 有些域名只涉及 http 请求,不涉及 https 的请求不需要证书,或者某些敏感及第三方域名无法获得证书,这类域名可以通过在 `配置 -> 入口配置` 里面设置:
138
+ ![入口配置](https://user-images.githubusercontent.com/29788452/104726133-0e211400-576e-11eb-9138-0ded4282bce5.png)
139
+
140
+ 入口配置的规则有三种(`#xxx`表示注释):
141
+ ``` txt
142
+ pattern #转发到Nohost,如果是html页面则注入小圆点
143
+ -pattern #转发到Nohost,不注入小圆点
144
+ --pattern #不转发到Nohost,且不注入小圆点
145
+ x)-pattern #x为整数(正负数零都可以),表示手动设置优先级,默认为0
146
+ ```
147
+ pattern 参见:[https://wproxy.org/whistle/pattern.html](https://wproxy.org/whistle/pattern.html),匹配顺序是从上到下,每个请求只会匹配其中一个,证书里面到域名优先级默认最低,可以通过 `1)` 设置优先级。
148
+
149
+ 如:
150
+ ``` txt
151
+ ke.qq.com
152
+ -*.url.cn
153
+ --localhost.**
154
+ -1)**.qq.com
155
+ ```
156
+ 表示:
157
+ 1. 所有 `ke.qq.com` 的请求都转发到Nohost,且所有 html 都注入小圆点
158
+ 2. 所有 `xxx.url.cn` 的请求都转发到Nohost,但不注入小圆点
159
+ 3. 所有 `localhost.xxx.yyy...` 的请求都不转发到Nohost,且不注入小圆点
160
+ 4. 所有 `qq.com` 的子代域名请求都转发到Nohost,但不注入小圆点,并优先级设为 `-1` ,确保证书里面的 `qq.com` 子域名可以正常注入小圆点
161
+
162
+ ## <a href="#whistle" id="whistle">七. 规则</a>
163
+ 这个是 Nohost 主进程 Whistle,所有请求都会通过该 Whistle,并通过该进程的 whistle.nohost 插件进行账号管理及请求转发,主进程 Whistle 在生产环境下无法查看抓包数据,可用于设置规则及全局插件管理,如:屏蔽一些请求等等,更多内容参见后面的文档。
164
+
165
+ **详细内容参见文档:[https://nohost.pro/](https://nohost.pro/)**
166
+
167
+ ## <a href="#development" id="development">八. 开发</a>
168
+ 开发环境搭建:
169
+ ```bash
170
+ git clone git@github.com:Tencent/nohost.git
171
+ # 切换到dev开发分支
172
+ git checkout dev
173
+ # 安装依赖
174
+ npm install
175
+ # 启动页面构建
176
+ npm run dev
177
+ # 启动 Nohost
178
+ npm start
179
+ ```
180
+ > 修改页面后需要手动刷新
181
+
182
+
183
+ ## <a href="#add" id="add">九. 加群</a>
184
+ 欢迎大家加入Nohost交流群。考虑到群二维码有时效限制,请大家扫码加好友,验证回复 `Nohost` ,会统一将大家拉进群。
185
+ ![二维码](https://user-images.githubusercontent.com/29788452/105933529-8bf7f000-6089-11eb-9e0a-6ab40604e355.png)
186
+
187
+ # 参与贡献
188
+ 如果你有好的意见或建议,欢迎给我们提 Issues 或 Pull Requests,为提升抓包调试体验贡献力量。
189
+ [腾讯开源激励计划](https://opensource.tencent.com/contribution) 鼓励开发者的参与和贡献,期待你的加入。
190
+ # License
191
+ [MIT](./LICENSE)
package/bin/nohost.js ADDED
@@ -0,0 +1,178 @@
1
+ #! /usr/bin/env node
2
+
3
+ /**
4
+ * Tencent is pleased to support the open source community by making nohost-环境配置与抓包调试平台 available.
5
+ * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. The below software in
6
+ * this distribution may have been modified by THL A29 Limited ("Tencent Modifications").
7
+ * All Tencent Modifications are Copyright (C) THL A29 Limited.
8
+ * nohost-环境配置与抓包调试平台 is licensed under the MIT License except for the third-party components listed below.
9
+ */
10
+ const w2 = require('whistle/bin/plugin');
11
+
12
+ const WHISTLE_PATH = process.env.NOHOST_PATH || w2.getWhistlePath();
13
+ process.env.WHISTLE_PATH = WHISTLE_PATH;
14
+
15
+ /* eslint no-console: "off" */
16
+ const program = require('starting');
17
+ const path = require('path');
18
+ const os = require('os');
19
+ const pkg = require('../package.json');
20
+ const util = require('./util');
21
+ const plugin = require('./plugin');
22
+
23
+ const { showUsage, error, warn, info } = util;
24
+ const { readConfig, removeConfig, getDefaultDir } = program.cli;
25
+
26
+ process.env.STARTING_DATA_DIR = path.join(os.homedir() || '~', '.NohostAppData');
27
+
28
+ function showStartupInfo(err, options, debugMode, restart) {
29
+ if (!err || err === true) {
30
+ return showUsage(err, options, restart);
31
+ }
32
+ // 处理端口冲突错误
33
+ if (/listen EADDRINUSE/.test(err)) {
34
+ options = util.formatOptions(options);
35
+ error(`[!] Failed to bind proxy port ${options.host ? `${options.host}:` : ''}${options.port || pkg.port}: The port is already in use`);
36
+ info(`[i] Please check if nohost is already running, you can ${debugMode ? 'stop nohost with `nohost stop` first' : 'restart nohost with `nohost restart`'}`);
37
+ info(` or if another application is using the port, you can change the port with ${debugMode ? '`nohost run -p newPort`\n' : '`nohost start -p newPort`\n'}`);
38
+ } else if (err.code === 'EACCES' || err.code === 'EPERM') {
39
+ error('[!] Cannot start nohost owned by root');
40
+ info('[i] Try to run command with `sudo`\n');
41
+ }
42
+
43
+ error(err.stack ? `Date: ${new Date().toLocaleString()}\n${err.stack}` : err);
44
+ }
45
+ function checkVersion(ver) {
46
+ if (!ver || typeof ver !== 'string') {
47
+ return;
48
+ }
49
+ const list = ver.split('.');
50
+ if (list[0] > 1 || list[0] === '0') {
51
+ return true;
52
+ }
53
+ return ver === '1.0.0' || ver === '1.0.1';
54
+ }
55
+
56
+ // 设置默认启动参数
57
+ program.setConfig({
58
+ main() {
59
+ const mainFile = path.join(__dirname, '../index.js');
60
+ const dataDir = getDefaultDir();
61
+ const { pid, version } = readConfig(mainFile, dataDir);
62
+ if (pid && checkVersion(version)) {
63
+ try {
64
+ process.kill(pid);
65
+ } catch (e) {}
66
+ removeConfig(mainFile, dataDir);
67
+ }
68
+ return mainFile;
69
+ },
70
+ name: 'nohost',
71
+ version: pkg.version,
72
+ runCallback(err, options) {
73
+ if (err) {
74
+ showStartupInfo(err, options, true);
75
+ return;
76
+ }
77
+ showUsage(false, options);
78
+ console.log('Press [Ctrl+C] to stop nohost...');
79
+ },
80
+ startCallback: showStartupInfo,
81
+ restartCallback(err, options) {
82
+ showStartupInfo(err, options, false, true);
83
+ },
84
+ stopCallback(err) {
85
+ if (err === true) {
86
+ info('[i] nohost killed.');
87
+ } else if (err) {
88
+ if (err.code === 'EPERM') {
89
+ util.showKillError();
90
+ } else {
91
+ error(`[!] ${err.message}`);
92
+ }
93
+ } else {
94
+ warn('[!] No running nohost');
95
+ }
96
+ },
97
+ });
98
+ // 安装插件命令
99
+ program
100
+ .command('install')
101
+ .description('Install the plugin');
102
+ // 卸载插件命令
103
+ program.command('uninstall')
104
+ .description('Uninstall the plugin');
105
+
106
+ let { argv } = process;
107
+ let cmd = argv[2];
108
+ const removeItem = (list, name) => {
109
+ const i = list.indexOf(name);
110
+ if (i !== -1) {
111
+ list.splice(i, 1);
112
+ }
113
+ };
114
+
115
+ const isGlobal = (params) => {
116
+ if (params.indexOf('-g') !== -1 || params.indexOf('--global') !== -1) {
117
+ removeItem(params, '-g');
118
+ removeItem(params, '--global');
119
+ return true;
120
+ }
121
+ };
122
+
123
+ const parseArgv = (isG) => {
124
+ const { account, args, plugins } = plugin.parseArgv(argv);
125
+ const baseDir = w2.getWhistlePath();
126
+ let dir;
127
+ if (isG) {
128
+ dir = path.join(baseDir, 'nohost_plugins/main_plugins');
129
+ } else {
130
+ dir = path.join(baseDir, `nohost_plugins/${account ? 'account' : 'worker'}_plugins/${account || ''}`);
131
+ }
132
+ return [`--dir=${dir}`].concat(plugins).concat(args);
133
+ };
134
+
135
+ // 处理非 starting 内置的命令
136
+ if (/^([a-z]{1,2})?uni(nstall)?$/.test(cmd)) {
137
+ argv = Array.prototype.slice.call(argv, 3);
138
+ const isG = isGlobal(argv);
139
+ if (!isG) {
140
+ plugin.uninstall(argv.slice());
141
+ }
142
+ w2.uninstall(parseArgv(isG));
143
+ } else if (/^([a-z]{1,2})?i(nstall)?$/.test(cmd)) {
144
+ cmd = `${RegExp.$1 || ''}npm`;
145
+ argv = Array.prototype.slice.call(argv, 3);
146
+ w2.install(cmd, parseArgv(isGlobal(argv)));
147
+ } else {
148
+ let index = argv.lastIndexOf('-n');
149
+ if (index === -1) {
150
+ index = argv.lastIndexOf('--username');
151
+ }
152
+ if (index === -1) {
153
+ argv.push('--username', '+');
154
+ }
155
+ program
156
+ .option('-p, --port [proxyPort]', 'set the listening port or host:port (8080 by default)', String, undefined)
157
+ .option('-n, --username [username]', 'set the username to admin', String, undefined)
158
+ .option('-w, --password [password]', 'set the password to admin', String, undefined)
159
+ .option('-k, --authKey [authKey]', 'set the authKey to admin', String, undefined)
160
+ .option('-o, --nohostDomain [domain]', 'set the nohost domain (as: nohost.imweb.io,xxx.yyy.com)', String, undefined)
161
+ .option('-a, --account <account>', 'set the account for installing the plugin (all accounts by default)', String, undefined)
162
+ .option('-b, --baseDir <dir>', 'set the configured storage root path', String, undefined)
163
+ .option('-s, --storage <host:port>', 'set the host:port of server to save the request data', String, undefined)
164
+ .option('-M, --mode [mode]', 'set the starting mode (as: prod)', String, undefined)
165
+ .option('-r, --shadowRules [shadowRules]', 'set shadow (default) rules', String, undefined)
166
+ .option('--globalPluginPath [globalPluginPath]', 'set the custom global plugin path (separated by comma)', String, undefined)
167
+ .option('--accountPluginPath [accountPluginPath]', 'set the custom account[worker] plugin path (separated by comma)', String, undefined)
168
+ .option('--config [config]', 'set whistle startup config from a local file', String, undefined)
169
+ .option('--dnsServer [dnsServer]', 'set custom dns servers', String, undefined);
170
+
171
+ if (argv.indexOf('--redirect') !== -1) {
172
+ program.option('--redirect <redirect>', 'redirect sedlect.html & data.html & share.html to new url', String, undefined);
173
+ }
174
+ if (argv.indexOf('--workerPluginPath') !== -1) {
175
+ program.option('--workerPluginPath <workerPluginPath>', 'set the custom account[worker] plugin path (separated by comma)', String, undefined);
176
+ }
177
+ program.parse(argv);
178
+ }
package/bin/plugin.js ADDED
@@ -0,0 +1,70 @@
1
+ const path = require('path');
2
+ const os = require('os');
3
+ const fs = require('fs');
4
+ const fse = require('fs-extra');
5
+
6
+ const PLUGINS_DIR = path.resolve(os.homedir(), 'whistle-plugins/whistle.nohost');
7
+ const WHISTLE_PLUGIN_RE = /^(@[\w-]+\/)?whistle\.[a-z\d_-]+$/;
8
+ const ACCOUNT_RE = /^[\w.-]{1,24}$/;
9
+
10
+ const getAccount = (argv) => {
11
+ let account;
12
+ for (let i = 0, len = argv.length; i < len; i++) {
13
+ const arg = argv[i];
14
+ if (['-a', '-w', '--account'].indexOf(arg) !== -1) {
15
+ account = argv[i + 1];
16
+ argv.splice(i, 2);
17
+ break;
18
+ }
19
+ if (/^--account=/.test(arg)) {
20
+ account = arg.substring(10);
21
+ argv.splice(i, 1);
22
+ break;
23
+ }
24
+ }
25
+ return account && ACCOUNT_RE.test(account) ? account : null;
26
+ };
27
+
28
+ const parseArgv = (argv) => {
29
+ argv = argv.slice();
30
+ const account = getAccount(argv);
31
+ const args = [];
32
+ const plugins = argv.filter((name) => {
33
+ if (WHISTLE_PLUGIN_RE.test(name)) {
34
+ return true;
35
+ }
36
+ args.push(name);
37
+ return false;
38
+ });
39
+ return {
40
+ account,
41
+ plugins,
42
+ args,
43
+ };
44
+ };
45
+
46
+ exports.parseArgv = parseArgv;
47
+
48
+ const removeDir = (dir) => {
49
+ if (fs.existsSync(dir)) { // eslint-disable-line
50
+ fse.removeSync(dir); // eslint-disable-line
51
+ }
52
+ };
53
+
54
+ exports.uninstall = (argv) => {
55
+ const { account, plugins } = parseArgv(argv);
56
+ if (!plugins.length) {
57
+ return;
58
+ }
59
+ if (account) {
60
+ plugins.forEach((name) => {
61
+ removeDir(path.join(PLUGINS_DIR, account, 'node_modules', name));
62
+ removeDir(path.join(PLUGINS_DIR, account, 'lib/node_modules', name));
63
+ });
64
+ } else {
65
+ plugins.forEach((name) => {
66
+ removeDir(path.join(PLUGINS_DIR, 'node_modules', name));
67
+ removeDir(path.join(PLUGINS_DIR, 'lib/node_modules', name));
68
+ });
69
+ }
70
+ };
package/bin/util.js ADDED
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Tencent is pleased to support the open source community by making nohost-环境配置与抓包调试平台 available.
3
+ * Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved. The below software in
4
+ * this distribution may have been modified by THL A29 Limited ("Tencent Modifications").
5
+ * All Tencent Modifications are Copyright (C) THL A29 Limited.
6
+ * nohost-环境配置与抓包调试平台 is licensed under the MIT License except for the third-party components listed below.
7
+ */
8
+
9
+ const os = require('os');
10
+ const colors = require('colors/safe');
11
+ const pkg = require('../package.json');
12
+
13
+ const isWin = process.platform === 'win32';
14
+
15
+ const formatOptions = (options) => {
16
+ if (!options || !/^(?:([\w.-]+):)?([1-9]\d{0,4})$/.test(options.port)) {
17
+ return options;
18
+ }
19
+ options.host = options.host || RegExp.$1;
20
+ options.port = parseInt(RegExp.$2, 10);
21
+ return options;
22
+ };
23
+
24
+ exports.formatOptions = formatOptions;
25
+ /* eslint-disable no-console */
26
+ function getIpList() {
27
+ const ipList = [];
28
+ const ifaces = os.networkInterfaces();
29
+ Object.keys(ifaces).forEach((ifname) => {
30
+ ifaces[ifname].forEach((iface) => {
31
+ if (iface.family === 'IPv4' || iface.family === 4) {
32
+ ipList.push(iface.address);
33
+ }
34
+ });
35
+ });
36
+ const index = ipList.indexOf('127.0.0.1');
37
+ if (index !== -1) {
38
+ ipList.splice(index, 1);
39
+ }
40
+ ipList.unshift('127.0.0.1');
41
+ return ipList;
42
+ }
43
+
44
+ function error(msg) {
45
+ console.log(colors.red(msg));
46
+ }
47
+
48
+ function warn(msg) {
49
+ console.log(colors.yellow(msg));
50
+ }
51
+
52
+ function info(msg) {
53
+ console.log(colors.green(msg));
54
+ }
55
+ exports.error = error;
56
+ exports.warn = warn;
57
+ exports.info = info;
58
+
59
+ function showKillError() {
60
+ error('[!] Cannot kill nohost owned by root');
61
+ info(`[i] Try to run command ${isWin ? 'as an administrator' : 'with `sudo`'}`);
62
+ }
63
+
64
+ exports.showKillError = showKillError;
65
+
66
+ function showUsage(isRunning, options, restart) {
67
+ if (isRunning) {
68
+ if (restart) {
69
+ showKillError();
70
+ } else {
71
+ warn(`[!] nohost@${pkg.version} is running`);
72
+ }
73
+ } else {
74
+ info(`[i] nohost@${pkg.version}${restart ? ' restarted' : ' started'}`);
75
+ }
76
+ const { host, port } = formatOptions(options);
77
+ const curPort = port ? options.port : pkg.port;
78
+ const list = host ? [host] : getIpList();
79
+ info(`[i] use your device to visit the following URL list, gets the ${colors.bold('IP')} of the URL you can access:`);
80
+ info(list.map((ip) => {
81
+ return ` http://${colors.bold(ip)}${curPort ? `:${curPort}` : ''}/`;
82
+ }).join('\n'));
83
+
84
+ warn(' Note: If all the above URLs are unable to access, check the firewall settings');
85
+ warn(` For help see ${colors.bold('https://nohost.pro/')}`);
86
+
87
+ if (parseInt(process.version.slice(1), 10) < 6) {
88
+ // eslint-disable-next-line
89
+ warn(colors.bold('\nWarning: The current Node version is too low, access https://nodejs.org to install the latest version, or may not be able to Capture HTTPS CONNECTs\n'));
90
+ }
91
+ }
92
+
93
+ exports.showUsage = showUsage;