whistle.script 1.2.0 → 1.2.4

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.
package/README.md CHANGED
@@ -201,6 +201,60 @@ exports.auth = async (req, options) => {
201
201
  };
202
202
  ```
203
203
 
204
+ 5. pipe
205
+ 插件 `v1.2.1` 版本开始支持自定义 pipe 方法:
206
+ ``` js
207
+
208
+ exports.handleReqRead = (req, res, options) => {
209
+ req.pipe(res);
210
+ };
211
+
212
+ exports.handleReqWrite = (req, res, options) => {
213
+ req.pipe(res);
214
+ };
215
+
216
+ exports.handleResRead = (req, res, options) => {
217
+ req.pipe(res);
218
+ };
219
+
220
+ exports.handleResWrite = (req, res, options) => {
221
+ req.pipe(res);
222
+ };
223
+
224
+ exports.handleWsReqRead = (req, res, options) => {
225
+ req.pipe(res);
226
+ };
227
+
228
+ exports.handleWsReqWrite = (req, res, options) => {
229
+ req.pipe(res);
230
+ };
231
+
232
+ exports.handleWsResRead = (req, res, options) => {
233
+ req.pipe(res);
234
+ };
235
+
236
+ exports.handleWsResWrite = (req, res, options) => {
237
+ req.pipe(res);
238
+ };
239
+
240
+ exports.handleTunnelReqRead = (req, res, options) => {
241
+ req.pipe(res);
242
+ };
243
+
244
+ exports.handleTunnelReqWrite = (req, res, options) => {
245
+ req.pipe(res);
246
+ };
247
+
248
+ exports.handleTunnelResRead = (req, res, options) => {
249
+ req.pipe(res);
250
+ };
251
+
252
+ exports.handleTunnelResWrite = (req, res, options) => {
253
+ req.pipe(res);
254
+ };
255
+
256
+ ```
257
+
204
258
  # 如何引入第三方模块
205
259
  使用绝对路径引入,如假设你的模块安装路径为 `/Users/test/node_modules/xxx`,则可以在脚本里面通过 `require('/Users/test/node_modules/xxx')` 引入。
206
260
 
package/lib/index.js CHANGED
@@ -1,7 +1,23 @@
1
+ const handlePipe = require('./pipe');
2
+
1
3
  exports.auth = require('./auth');
4
+ exports.sniCallback = require('./sniCallback');
2
5
  exports.uiServer = require('./uiServer');
3
6
  exports.rulesServer = require('./rulesServer');
4
7
  exports.resRulesServer = require('./resRulesServer');
5
8
  exports.tunnelRulesServer = require('./tunnelRulesServer');
6
9
  exports.server = require('./server');
7
10
  exports.tunnelServer = require('./tunnelServer');
11
+
12
+ exports.reqRead = handlePipe('reqRead');
13
+ exports.reqWrite = handlePipe('reqWrite');
14
+ exports.resRead = handlePipe('resRead');
15
+ exports.resWrite = handlePipe('resWrite');
16
+ exports.wsReqRead = handlePipe('wsReqRead');
17
+ exports.wsReqWrite = handlePipe('wsReqWrite');
18
+ exports.wsResRead = handlePipe('wsResRead');
19
+ exports.wsResWrite = handlePipe('wsResWrite');
20
+ exports.tunnelReqRead = handlePipe('tunnelReqRead');
21
+ exports.tunnelReqWrite = handlePipe('tunnelReqWrite');
22
+ exports.tunnelResRead = handlePipe('tunnelResRead');
23
+ exports.tunnelResWrite = handlePipe('tunnelResWrite');
package/lib/pipe.js ADDED
@@ -0,0 +1,32 @@
1
+ const iconv = require('iconv-lite');
2
+ const scripts = require('./scripts');
3
+ const util = require('./util');
4
+
5
+ const getHandlerName = (name) => {
6
+ return `handle${name[0].toUpperCase()}${name.substring(1)}`;
7
+ };
8
+
9
+ module.exports = (name) => {
10
+ const eventName = name[0] === 'r' ? 'request' : 'connect';
11
+ return (server, options) => {
12
+ options = Object.assign({
13
+ getCharset: util.getCharset,
14
+ isText: util.isText,
15
+ iconv,
16
+ }, options);
17
+ server.on(eventName, async (req, res) => {
18
+ const oReq = req.originalReq;
19
+ oReq.ruleValue = oReq.pipeValue || oReq.ruleValue;
20
+ const handleRequest = scripts.getHandler({ req })[getHandlerName(name)];
21
+ if (!util.isFunction(handleRequest)) {
22
+ return req.pipe(res);
23
+ }
24
+ try {
25
+ await handleRequest(req, res, options);
26
+ } catch (err) {
27
+ req.emit('error', err);
28
+ console.error(err); // eslint-disable-line
29
+ }
30
+ });
31
+ };
32
+ };
package/lib/server.js CHANGED
@@ -24,6 +24,8 @@ module.exports = (server, options) => {
24
24
  await handleRequest(ctx, req.request);
25
25
  } catch (err) {
26
26
  clearup();
27
+ req.emit('error', err);
28
+ console.error(err); // eslint-disable-line
27
29
  }
28
30
  });
29
31
  setupWsServer(server, options);
@@ -0,0 +1,24 @@
1
+ const scripts = require('./scripts');
2
+ const { getRemoteUrl, getContext, getFn, request, SNI_URL, isSni } = require('./util');
3
+
4
+ module.exports = async (req, options) => {
5
+ if (!isSni(req)) {
6
+ const oReq = req.originalReq;
7
+ oReq.ruleValue = oReq.sniValue || oReq.ruleValue;
8
+ const ctx = getContext(req);
9
+ const { sniCallback, SNICallback } = scripts.getHandler(ctx);
10
+ const sniCb = getFn(sniCallback, SNICallback);
11
+ return sniCb && sniCb(req, options);
12
+ }
13
+ const sniUrl = getRemoteUrl(req, SNI_URL);
14
+ if (sniUrl) {
15
+ const result = await request(sniUrl, req.headers);
16
+ if (result === false || result.cert === false) {
17
+ return false;
18
+ }
19
+ if (result === true || result.cert === true) {
20
+ return true;
21
+ }
22
+ return result;
23
+ }
24
+ };
package/lib/util.js CHANGED
@@ -2,9 +2,11 @@ const zlib = require('zlib');
2
2
  const { EventEmitter } = require('events');
3
3
  const { parse: parseUrl } = require('url');
4
4
  const http = require('http');
5
+ const https = require('https');
5
6
  const dataSource = require('./dataSource');
6
7
 
7
8
  exports.AUTH_URL = 'x-whistle-.script-auth-url';
9
+ exports.SNI_URL = 'x-whistle-.script-sni-url';
8
10
  exports.REQ_RULES_URL = 'x-whistle-.script-req-rules-url';
9
11
  exports.RES_RULES_URL = 'x-whistle-.script-res-rules-url';
10
12
  exports.STATS_URL = 'x-whistle-.script-stats-url';
@@ -13,7 +15,7 @@ exports.noop = () => {};
13
15
 
14
16
  const POLICY = 'x-whistle-.script-policy';
15
17
  const isFunction = fn => typeof fn === 'function';
16
- const URL_RE = /^http:(?:\/\/|%3A%2F%2F)[\w.-]/;
18
+ const URL_RE = /^https?:(?:\/\/|%3A%2F%2F)[\w.-]/;
17
19
 
18
20
  exports.isFunction = isFunction;
19
21
  exports.noop = () => {};
@@ -140,7 +142,9 @@ const request = (url, headers, data) => {
140
142
  options.method = 'POST';
141
143
  }
142
144
  return new Promise((resolve, reject) => {
143
- const client = http.request(options, (res) => {
145
+ const httpModule = options.protocol === 'https:' ? https : http;
146
+ options.rejectUnauthorized = false;
147
+ const client = httpModule.request(options, (res) => {
144
148
  res.on('error', handleError); // eslint-disable-line
145
149
  let body;
146
150
  res.on('data', (chunk) => {
@@ -177,10 +181,23 @@ exports.request = async (url, headers, data) => {
177
181
  }
178
182
  };
179
183
 
180
- const isRemote = ({ headers }) => (headers[POLICY] === 'remote');
184
+ const hasPolicy = ({ headers }, name) => {
185
+ const policy = headers[POLICY];
186
+ if (typeof policy === 'string') {
187
+ return policy.toLowerCase().indexOf(name) !== -1;
188
+ }
189
+ };
190
+
191
+ const isRemote = (req) => {
192
+ return hasPolicy(req, 'remote');
193
+ };
181
194
 
182
195
  exports.isRemote = isRemote;
183
196
 
197
+ exports.isSni = (req) => {
198
+ return hasPolicy(req, 'sni');
199
+ };
200
+
184
201
  exports.getRemoteUrl = (req, name) => {
185
202
  let url = req.headers[name];
186
203
  if (typeof url === 'string') {
package/lib/wsServer.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const crypto = require('crypto');
2
+ const iconv = require('iconv-lite');
2
3
  const { getDataSource, getFn } = require('./util');
3
4
  const scripts = require('./scripts');
4
5
 
@@ -54,6 +55,7 @@ module.exports = (server, options) => {
54
55
  req.on('error', clearup);
55
56
  socket.dataSource = dataSource;
56
57
  socket.headers = headers;
58
+ socket.iconv = iconv;
57
59
  socket.url = socket.fullUrl = oReq.url; // eslint-disable-line
58
60
  const handleUpgrade = (res) => {
59
61
  if (replied) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "whistle.script",
3
3
  "description": "The plugin for the extension script for whistle",
4
- "version": "1.2.0",
4
+ "version": "1.2.4",
5
5
  "author": "avenwu <avenwu@vip.qq.com>",
6
6
  "contributors": [],
7
7
  "license": "MIT",
@@ -15,6 +15,9 @@
15
15
  "ssi"
16
16
  ],
17
17
  "registry": "https://github.com/whistle-plugins/whistle.script",
18
+ "whistleConfig": {
19
+ "pluginVars": true
20
+ },
18
21
  "repository": {
19
22
  "type": "git",
20
23
  "url": "https://github.com/whistle-plugins/whistle.script.git"
package/rules.txt CHANGED
@@ -1 +1,2 @@
1
1
  * whistle.script:// includeFilter://reqH.x-whistle-.script-policy=remote
2
+ * sniCallback://script includeFilter://reqH.x-whistle-.script-policy=sni