From 6fcb1a2b9160a85c6f4f80cd21e6bd9a352f53b0 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Fri, 21 Mar 2014 15:05:16 +0800 Subject: [PATCH 01/76] Heroku support --- .travis.yml | 2 +- shadowsocks/Cakefile => Cakefile | 0 shadowsocks/Procfile => Procfile | 0 README.md | 89 ++++++++++++++-------- shadowsocks/args.js => args.js | 3 +- config.json | 7 ++ dotcloud.yml | 5 -- shadowsocks/encrypt.js => encrypt.js | 3 +- shadowsocks/local.js => local.js | 7 +- shadowsocks/merge_sort.js => merge_sort.js | 2 +- package.json | 9 +++ shadowsocks/server.js => server.js | 9 ++- shadowsocks/config.json | 7 -- shadowsocks/package.json | 10 --- shadowsocks/supervisord.conf | 3 - {shadowsocks/src => src}/args.coffee | 0 {shadowsocks/src => src}/encrypt.coffee | 0 {shadowsocks/src => src}/local.coffee | 0 {shadowsocks/src => src}/merge_sort.coffee | 0 {shadowsocks/src => src}/server.coffee | 4 +- {shadowsocks/src => src}/test.coffee | 0 shadowsocks/test.js => test.js | 2 +- {shadowsocks/test => test}/config.json | 0 shadowsocks/test_http.js => test_http.js | 0 shadowsocks/web.js => web.js | 0 25 files changed, 90 insertions(+), 72 deletions(-) rename shadowsocks/Cakefile => Cakefile (100%) rename shadowsocks/Procfile => Procfile (100%) rename shadowsocks/args.js => args.js (95%) create mode 100644 config.json delete mode 100644 dotcloud.yml rename shadowsocks/encrypt.js => encrypt.js (98%) rename shadowsocks/local.js => local.js (98%) rename shadowsocks/merge_sort.js => merge_sort.js (95%) create mode 100644 package.json rename shadowsocks/server.js => server.js (97%) delete mode 100644 shadowsocks/config.json delete mode 100644 shadowsocks/package.json delete mode 100644 shadowsocks/supervisord.conf rename {shadowsocks/src => src}/args.coffee (100%) rename {shadowsocks/src => src}/encrypt.coffee (100%) rename {shadowsocks/src => src}/local.coffee (100%) rename {shadowsocks/src => src}/merge_sort.coffee (100%) rename {shadowsocks/src => src}/server.coffee (99%) rename {shadowsocks/src => src}/test.coffee (100%) rename shadowsocks/test.js => test.js (99%) rename {shadowsocks/test => test}/config.json (100%) rename shadowsocks/test_http.js => test_http.js (100%) rename shadowsocks/web.js => web.js (100%) diff --git a/.travis.yml b/.travis.yml index 77637270..d7390186 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,10 @@ language: node_js node_js: + - "0.10" - "0.8" - "0.6" before_install: - npm install -g coffee-script - - cd shadowsocks - cp test/config.json . script: - cake build diff --git a/shadowsocks/Cakefile b/Cakefile similarity index 100% rename from shadowsocks/Cakefile rename to Cakefile diff --git a/shadowsocks/Procfile b/Procfile similarity index 100% rename from shadowsocks/Procfile rename to Procfile diff --git a/README.md b/README.md index 7bcf65df..1027447b 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,80 @@ -shadowsocks-dotcloud -=========== +shadowsocks-heroku +================== -[![Build Status](https://travis-ci.org/clowwindy/shadowsocks-dotcloud.png)](https://travis-ci.org/clowwindy/shadowsocks-dotcloud) - -shadowsocks-dotcloud is a lightweight tunnel proxy which can help you get through +shadowsocks-heroku is a lightweight tunnel proxy which can help you get through firewalls. It is a port of [shadowsocks](https://github.com/clowwindy/shadowsocks), but through a different protocol. -shadowsocks-dotcloud uses WebSockets instead of raw sockets, - so it can be deployed on [dotcloud](https://www.dotcloud.com/). +shadowsocks-heroku uses WebSockets instead of raw sockets, + so it can be deployed on [heroku](https://www.heroku.com/). Notice that the protocol is INCOMPATIBLE with the origin shadowsocks. -usage ------------ - -Sign up for [dotcloud](https://www.dotcloud.com/). +Usage +----- -Install [dotcloud CLI](https://docs.dotcloud.com/0.9/firststeps/install/). + $ heroku create + Creating still-tor-8707... done, stack is cedar + http://still-tor-8707.herokuapp.com/ | git@heroku.com:still-tor-8707.git -Put the code somewhere, for example shadowsocks-dotcloud/. Edit `shadowsocks/config.json`, change the following values: +Put the code somewhere, for example shadowsocks-heroku/. Edit `config.json`, change the following values: - server your server hostname, for example, shadowsocks-YOURUSERNAME.dotcloud.com + server your server hostname, for example: still-tor-8707.herokuapp.com local_port local port password a password used to encrypt transfer timeout in seconds - method encryption method, null by default, or use "rc4" - -Upload the code. You can choose your own app name other than `shadowsocks`. You'll see your hostname at the end. - - $ dotcloud create shadowsocks - Created application "shadowsocks" using the flavor "sandbox" - ... - $ dotcloud push --application shadowsocks shadowsocks-dotcloud/ - # upload shadowsocks-dotcloud/ ssh://dotcloud@uploader.dotcloud.com:443/shadowsocks - ... - Deployment finished. Your application is available at the following URLs - www: http://shadowsocks-YOURUSERNAME.dotcloud.com/ - -Open terminal, cd into shadowsocks, run `node local.js`. + method encryption method, "rc4" by default + +Push the code to heroku. + +``` +$ git push heroku master +Initializing repository, done. +Counting objects: 178, done. +Delta compression using up to 4 threads. +Compressing objects: 100% (97/97), done. +Writing objects: 100% (178/178), 47.42 KiB | 0 bytes/s, done. +Total 178 (delta 89), reused 162 (delta 78) + +-----> Node.js app detected +-----> Requested node range: 0.10.x +-----> Resolved node version: 0.10.26 +-----> Downloading and installing node +-----> Writing a custom .npmrc to circumvent npm bugs +-----> Exporting config vars to environment +-----> Installing dependencies + npm WARN package.json shadowsocks-heroku@0.9.6 No repository field. +-----> Cleaning up node-gyp and npm artifacts +-----> Building runtime environment +-----> Discovering process types + Procfile declares types -> web + +-----> Compressing... done, 5.1MB +-----> Launching... done, v3 + http://still-tor-8707.herokuapp.com/ deployed to Heroku + +To git@heroku.com:still-tor-8707.git + * [new branch] master -> master +``` + +While in beta, WebSocket functionality must be enabled via the Heroku Labs: + +``` +$ heroku labs:enable websockets +Enabling websockets for still-tor-8707... done +WARNING: This feature is experimental and may change or be removed without notice. +For more information see: https://devcenter.heroku.com/articles/heroku-labs-websockets +``` + +Open terminal, run `node local.js`. Change proxy settings of your browser into SOCKS5 127.0.0.1:local_port - -troubleshooting +Troubleshooting ---------------- If there is something wrong, you can check the logs by: - $ dotcloud logs www --application shadowsocks + $ heroku logs -t --app still-tor-8707 diff --git a/shadowsocks/args.js b/args.js similarity index 95% rename from shadowsocks/args.js rename to args.js index 50b5173b..4f4c6cbc 100644 --- a/shadowsocks/args.js +++ b/args.js @@ -1,6 +1,5 @@ -// Generated by CoffeeScript 1.4.0 +// Generated by CoffeeScript 1.7.1 (function() { - exports.parseArgs = function() { var defination, lastKey, nextIsValue, oneArg, result, _, _ref; defination = { diff --git a/config.json b/config.json new file mode 100644 index 00000000..d78679ca --- /dev/null +++ b/config.json @@ -0,0 +1,7 @@ +{ + "server": ["still-tor-8707.herokuapp.com"], + "local_port": 1080, + "password": "`try*(^^$some^$%^complex>:<>?~password/", + "timeout": 600, + "method": "rc4" +} diff --git a/dotcloud.yml b/dotcloud.yml deleted file mode 100644 index f97a8aa1..00000000 --- a/dotcloud.yml +++ /dev/null @@ -1,5 +0,0 @@ -www: - type: nodejs - approot: shadowsocks - config: - node_version: v0.8.x \ No newline at end of file diff --git a/shadowsocks/encrypt.js b/encrypt.js similarity index 98% rename from shadowsocks/encrypt.js rename to encrypt.js index e680b956..e040c57d 100644 --- a/shadowsocks/encrypt.js +++ b/encrypt.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.4.0 +// Generated by CoffeeScript 1.7.1 (function() { var Encryptor, cachedTables, crypto, encrypt, getTable, int32Max, merge_sort, util; @@ -58,7 +58,6 @@ }; Encryptor = (function() { - function Encryptor(key, method) { var _ref; this.method = method; diff --git a/shadowsocks/local.js b/local.js similarity index 98% rename from shadowsocks/local.js rename to local.js index ea85c649..90935833 100644 --- a/shadowsocks/local.js +++ b/local.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.4.0 +// Generated by CoffeeScript 1.7.1 (function() { var Encryptor, KEY, METHOD, PORT, REMOTE_PORT, SERVER, args, config, configContent, configFromArgs, fs, getServer, http, inetAton, inetNtoa, k, net, path, server, timeout, util, v; @@ -85,7 +85,7 @@ addrToSend = ""; aServer = getServer(); connection.on("data", function(data) { - var addrtype, buf, cmd, reply, tempBuf; + var addrtype, buf, cmd, e, reply, tempBuf; if (stage === 5) { data = encryptor.encrypt(data); if (!remote.write(data)) { @@ -206,7 +206,8 @@ buf = null; } return stage = 4; - } catch (e) { + } catch (_error) { + e = _error; util.log(e); connection.destroy(); if (remote) { diff --git a/shadowsocks/merge_sort.js b/merge_sort.js similarity index 95% rename from shadowsocks/merge_sort.js rename to merge_sort.js index ed5188bb..6701609f 100644 --- a/shadowsocks/merge_sort.js +++ b/merge_sort.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.4.0 +// Generated by CoffeeScript 1.7.1 (function() { var merge, merge_sort; diff --git a/package.json b/package.json new file mode 100644 index 00000000..a41eb460 --- /dev/null +++ b/package.json @@ -0,0 +1,9 @@ +{ + "name": "shadowsocks-heroku", + "version": "0.9.6", + "dependencies": { + }, + "engines": { + "node": "0.10.x" + } +} diff --git a/shadowsocks/server.js b/server.js similarity index 97% rename from shadowsocks/server.js rename to server.js index 7ef77df8..935aae9d 100644 --- a/shadowsocks/server.js +++ b/server.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.4.0 +// Generated by CoffeeScript 1.7.1 (function() { var Encryptor, KEY, METHOD, PORT, args, config, configContent, configFile, configFromArgs, fs, http, inetAton, inetNtoa, k, net, path, portPassword, server, timeout, v; @@ -53,7 +53,7 @@ portPassword = config.port_password; - PORT = 8080; + PORT = process.env.PORT || 8080; KEY = config.password; @@ -80,7 +80,7 @@ remoteAddr = null; remotePort = null; connection.on("data", function(data) { - var addrtype, buf; + var addrtype, buf, e; data = encryptor.decrypt(data); if (stage === 5) { if (!remote.write(data)) { @@ -150,7 +150,8 @@ buf = null; } return stage = 4; - } catch (e) { + } catch (_error) { + e = _error; console.warn(e); connection.destroy(); if (remote) { diff --git a/shadowsocks/config.json b/shadowsocks/config.json deleted file mode 100644 index 363bec9b..00000000 --- a/shadowsocks/config.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "server":["projectname-username.dotcloud.com"], - "local_port":1080, - "password":"`try*(^^$some^$%^complex>:<>?~password/", - "timeout":600, - "method":null -} diff --git a/shadowsocks/package.json b/shadowsocks/package.json deleted file mode 100644 index bc4a4eed..00000000 --- a/shadowsocks/package.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "shadowsocks-dotcloud", - "version": "0.9.6", - "dependencies": { - }, - "engines": { - "node": "0.8.x", - "npm": "1.1.x" - } -} \ No newline at end of file diff --git a/shadowsocks/supervisord.conf b/shadowsocks/supervisord.conf deleted file mode 100644 index 5995eeee..00000000 --- a/shadowsocks/supervisord.conf +++ /dev/null @@ -1,3 +0,0 @@ -[program:node] -command = node server.js -directory = /home/dotcloud/current \ No newline at end of file diff --git a/shadowsocks/src/args.coffee b/src/args.coffee similarity index 100% rename from shadowsocks/src/args.coffee rename to src/args.coffee diff --git a/shadowsocks/src/encrypt.coffee b/src/encrypt.coffee similarity index 100% rename from shadowsocks/src/encrypt.coffee rename to src/encrypt.coffee diff --git a/shadowsocks/src/local.coffee b/src/local.coffee similarity index 100% rename from shadowsocks/src/local.coffee rename to src/local.coffee diff --git a/shadowsocks/src/merge_sort.coffee b/src/merge_sort.coffee similarity index 100% rename from shadowsocks/src/merge_sort.coffee rename to src/merge_sort.coffee diff --git a/shadowsocks/src/server.coffee b/src/server.coffee similarity index 99% rename from shadowsocks/src/server.coffee rename to src/server.coffee index 8e2b5ab9..f28a4c73 100644 --- a/shadowsocks/src/server.coffee +++ b/src/server.coffee @@ -50,7 +50,7 @@ for k, v of configFromArgs config[k] = v timeout = Math.floor(config.timeout * 1000) portPassword = config.port_password -PORT = 8080 +PORT = process.env.PORT || 8080 KEY = config.password METHOD = config.method #SERVER = config.server @@ -119,7 +119,7 @@ server.on 'upgrade', (req, connection, head) -> console.log "remote disconnected" console.log "concurrent connections: " + server.connections connection.end() - + remote.on "error", (e)-> console.log "remote : #{e}" connection.destroy() diff --git a/shadowsocks/src/test.coffee b/src/test.coffee similarity index 100% rename from shadowsocks/src/test.coffee rename to src/test.coffee diff --git a/shadowsocks/test.js b/test.js similarity index 99% rename from shadowsocks/test.js rename to test.js index 8a934d38..c5d2a266 100644 --- a/shadowsocks/test.js +++ b/test.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.4.0 +// Generated by CoffeeScript 1.7.1 (function() { var child_process, curlRunning, encrypt, i, local, localReady, runCurl, server, serverReady, tables, target; diff --git a/shadowsocks/test/config.json b/test/config.json similarity index 100% rename from shadowsocks/test/config.json rename to test/config.json diff --git a/shadowsocks/test_http.js b/test_http.js similarity index 100% rename from shadowsocks/test_http.js rename to test_http.js diff --git a/shadowsocks/web.js b/web.js similarity index 100% rename from shadowsocks/web.js rename to web.js From 6d0be0598bd7e7005619c639b6d1636830bb3345 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 8 Jul 2014 14:06:28 +0800 Subject: [PATCH 02/76] WebSocket now Generally Available on Heroku. https://blog.heroku.com/archives/2014/7/7/websockets_now_ga --- README.md | 29 +++++++++++++---------------- args.js | 2 +- server.js | 4 ++-- src/args.coffee | 6 +++--- src/server.coffee | 6 ++---- 5 files changed, 21 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 1027447b..3682b235 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,6 @@ Usage Creating still-tor-8707... done, stack is cedar http://still-tor-8707.herokuapp.com/ | git@heroku.com:still-tor-8707.git -Put the code somewhere, for example shadowsocks-heroku/. Edit `config.json`, change the following values: - - server your server hostname, for example: still-tor-8707.herokuapp.com - local_port local port - password a password used to encrypt transfer - timeout in seconds - method encryption method, "rc4" by default - Push the code to heroku. ``` @@ -57,20 +49,25 @@ To git@heroku.com:still-tor-8707.git * [new branch] master -> master ``` -While in beta, WebSocket functionality must be enabled via the Heroku Labs: +Set a few configs: ``` -$ heroku labs:enable websockets -Enabling websockets for still-tor-8707... done -WARNING: This feature is experimental and may change or be removed without notice. -For more information see: https://devcenter.heroku.com/articles/heroku-labs-websockets +$ heroku config:set METHOD=rc4 KEY=foobar +Setting config vars and restarting still-tor-8707... done, v11 +KEY: foobar +METHOD: rc4 ``` -Open terminal, run `node local.js`. +Then run: + +``` +$ node local.js -s still-tor-8707.herokuapp.com -l 1080 -m rc4 -k foobar +shadowsocks-heroku v0.9.6 +``` -Change proxy settings of your browser into +Change proxy settings of your browser into: - SOCKS5 127.0.0.1:local_port + SOCKS5 127.0.0.1:1080 Troubleshooting ---------------- diff --git a/args.js b/args.js index 4f4c6cbc..fd96cc80 100644 --- a/args.js +++ b/args.js @@ -26,6 +26,6 @@ return result; }; - exports.version = "shadowsocks-dotcloud v0.9.6"; + exports.version = "shadowsocks-heroku v0.9.6"; }).call(this); diff --git a/server.js b/server.js index 935aae9d..993bd946 100644 --- a/server.js +++ b/server.js @@ -55,9 +55,9 @@ PORT = process.env.PORT || 8080; - KEY = config.password; + KEY = process.env.KEY || config.password; - METHOD = config.method; + METHOD = process.env.METHOD || config.method; server = http.createServer(function(req, res) { res.writeHead(200, { diff --git a/src/args.coffee b/src/args.coffee index 77ccb1e6..45c61476 100644 --- a/src/args.coffee +++ b/src/args.coffee @@ -6,8 +6,8 @@ exports.parseArgs = -> '-k': 'password', '-c': 'config_file', '-m': 'method' - - + + result = {} nextIsValue = false lastKey = null @@ -20,4 +20,4 @@ exports.parseArgs = -> nextIsValue = true result -exports.version = "shadowsocks-dotcloud v0.9.6" \ No newline at end of file +exports.version = "shadowsocks-heroku v0.9.6" diff --git a/src/server.coffee b/src/server.coffee index f28a4c73..d95d3773 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -51,10 +51,8 @@ for k, v of configFromArgs timeout = Math.floor(config.timeout * 1000) portPassword = config.port_password PORT = process.env.PORT || 8080 -KEY = config.password -METHOD = config.method -#SERVER = config.server - +KEY = process.env.KEY || config.password +METHOD = process.env.METHOD || config.method server = http.createServer (req, res) -> res.writeHead 200, 'Content-Type':'text/plain' From 5cda3dae4216f3def8021b7dfbec072cc0e08d4b Mon Sep 17 00:00:00 2001 From: Hui Zheng Date: Mon, 13 Oct 2014 10:34:39 +0800 Subject: [PATCH 03/76] support custom client-side configuration file from arguments --- local.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/local.js b/local.js index 90935833..6c52d8a3 100644 --- a/local.js +++ b/local.js @@ -38,11 +38,11 @@ } }; - configContent = fs.readFileSync(path.resolve(__dirname, "config.json")); + configFromArgs = args.parseArgs(); - config = JSON.parse(configContent); + configContent = fs.readFileSync(configFromArgs.config_file || path.resolve(__dirname, "config.json")); - configFromArgs = args.parseArgs(); + config = JSON.parse(configContent); for (k in configFromArgs) { v = configFromArgs[k]; From 46471dfc02e269165ec25b33772057a94668729f Mon Sep 17 00:00:00 2001 From: Hui Zheng Date: Mon, 13 Oct 2014 11:53:07 +0800 Subject: [PATCH 04/76] support custom client-side configuration file from arguments(change coffeescript) --- src/local.coffee | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/local.coffee b/src/local.coffee index d8a92dd9..d2b6170a 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -44,9 +44,9 @@ inetAton = (ipStr) -> i++ buf -configContent = fs.readFileSync(path.resolve(__dirname, "config.json")) -config = JSON.parse(configContent) configFromArgs = args.parseArgs() +configContent = fs.readFileSync(configFromArgs.config_file || path.resolve(__dirname, "config.json")) +config = JSON.parse(configContent) for k, v of configFromArgs config[k] = v SERVER = config.server From 41cda79ec5e85ac726bae7a32cbd56c7ab9f39a4 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 25 Dec 2014 12:26:35 +0800 Subject: [PATCH 05/76] Added `remote_port`, `local_address` options. --- Cakefile | 5 ++--- args.js | 6 ++++-- encrypt.js | 8 +++---- local.js | 44 ++++++++++++++++++++------------------- merge_sort.js | 2 +- package.json | 5 ++--- server.js | 12 +++++------ src/args.coffee | 5 +++-- src/encrypt.coffee | 13 ++++++------ src/local.coffee | 52 ++++++++++++++++++++++++---------------------- src/server.coffee | 20 +++++++++--------- test.js | 2 +- 12 files changed, 88 insertions(+), 86 deletions(-) diff --git a/Cakefile b/Cakefile index 48d8a5c1..cfaed85d 100644 --- a/Cakefile +++ b/Cakefile @@ -1,4 +1,3 @@ -{print} = require 'util' {spawn} = require 'child_process' build = (callback) -> @@ -11,7 +10,7 @@ build = (callback) -> coffee.stderr.on 'data', (data) -> process.stderr.write data.toString() coffee.stdout.on 'data', (data) -> - print data.toString() + console.log data.toString() coffee.on 'exit', (code) -> console.log 'build completed' callback?() if code is 0 @@ -23,7 +22,7 @@ test = (callback) -> coffee.stderr.on 'data', (data) -> process.stderr.write data.toString() coffee.stdout.on 'data', (data) -> - print data.toString() + console.log data.toString() coffee.on 'exit', (code) -> callback?() if code is 0 process.exit code diff --git a/args.js b/args.js index fd96cc80..9c1633cf 100644 --- a/args.js +++ b/args.js @@ -1,10 +1,12 @@ -// Generated by CoffeeScript 1.7.1 +// Generated by CoffeeScript 1.8.0 (function() { exports.parseArgs = function() { var defination, lastKey, nextIsValue, oneArg, result, _, _ref; defination = { + '-b': 'local_address', '-l': 'local_port', '-s': 'server', + '-r': 'remote_port', '-k': 'password', '-c': 'config_file', '-m': 'method' @@ -26,6 +28,6 @@ return result; }; - exports.version = "shadowsocks-heroku v0.9.6"; + exports.version = "shadowsocks-heroku v0.9.7"; }).call(this); diff --git a/encrypt.js b/encrypt.js index e040c57d..ee58ab75 100644 --- a/encrypt.js +++ b/encrypt.js @@ -1,11 +1,9 @@ -// Generated by CoffeeScript 1.7.1 +// Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, cachedTables, crypto, encrypt, getTable, int32Max, merge_sort, util; + var Encryptor, cachedTables, crypto, encrypt, getTable, int32Max, merge_sort; crypto = require("crypto"); - util = require("util"); - merge_sort = require("./merge_sort").merge_sort; int32Max = Math.pow(2, 32); @@ -17,7 +15,7 @@ if (cachedTables[key]) { return cachedTables[key]; } - util.log("calculating ciphers"); + console.log("calculating ciphers"); table = new Array(256); decrypt_table = new Array(256); md5sum = crypto.createHash("md5"); diff --git a/local.js b/local.js index 6c52d8a3..672f8b6d 100644 --- a/local.js +++ b/local.js @@ -1,6 +1,6 @@ -// Generated by CoffeeScript 1.7.1 +// Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, KEY, METHOD, PORT, REMOTE_PORT, SERVER, args, config, configContent, configFromArgs, fs, getServer, http, inetAton, inetNtoa, k, net, path, server, timeout, util, v; + var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SERVER, args, config, configContent, configFromArgs, fs, getServer, http, inetAton, inetNtoa, k, net, path, server, timeout, v; net = require("net"); @@ -10,8 +10,6 @@ path = require("path"); - util = require('util'); - args = require('./args'); Encryptor = require("./encrypt").Encryptor; @@ -53,6 +51,8 @@ REMOTE_PORT = config.remote_port || 80; + LOCAL_ADDRESS = config.local_address || '127.0.0.1'; + PORT = config.local_port; KEY = config.password; @@ -71,8 +71,8 @@ server = net.createServer(function(connection) { var aServer, addrLen, addrToSend, cachedPieces, encryptor, headerLength, remote, remoteAddr, remotePort, req, stage; - util.log("local connected"); - util.log("concurrent connections: " + server.connections); + console.log("local connected"); + console.log("concurrent connections:", server.connections); encryptor = new Encryptor(KEY, METHOD); stage = 0; headerLength = 0; @@ -105,7 +105,7 @@ cmd = data[1]; addrtype = data[3]; if (cmd !== 1) { - util.log("unsupported cmd: " + cmd); + console.log("unsupported cmd:", cmd); reply = new Buffer("\u0005\u0007\u0000\u0001", "binary"); connection.end(reply); return; @@ -113,7 +113,7 @@ if (addrtype === 3) { addrLen = data[4]; } else if (addrtype !== 1) { - util.log("unsupported addrtype: " + addrtype); + console.log("unsupported addrtype:", addrtype); connection.end(); return; } @@ -157,8 +157,8 @@ req.on('upgrade', function(res, conn, upgradeHead) { var addrToSendBuf, i, piece; remote = conn; - util.log("remote got upgrade"); - util.log("connecting " + remoteAddr + " via " + aServer); + console.log("remote got upgrade"); + console.log("connecting " + remoteAddr + " via " + aServer); addrToSendBuf = new Buffer(addrToSend, "binary"); addrToSendBuf = encryptor.encrypt(addrToSendBuf); remote.write(addrToSendBuf); @@ -178,18 +178,18 @@ } }); remote.on("end", function() { - util.log("remote disconnected"); + console.log("remote disconnected"); connection.end(); - return util.log("concurrent connections: " + server.connections); + return console.log("concurrent connections:", server.connections); }); remote.on("error", function(e) { - util.log("remote " + remoteAddr + ":" + remotePort + " error: " + e); + console.log("remote " + remoteAddr + ":" + remotePort + " error: " + e); if (stage === 4) { connection.destroy(); return; } connection.end(); - return util.log("concurrent connections: " + server.connections); + return console.log("concurrent connections:", server.connections); }); remote.on("drain", function() { return connection.resume(); @@ -208,7 +208,7 @@ return stage = 4; } catch (_error) { e = _error; - util.log(e); + console.log(e); connection.destroy(); if (remote) { return remote.destroy(); @@ -224,17 +224,17 @@ if (remote) { remote.destroy(); } - return util.log("concurrent connections: " + server.connections); + return console.log("concurrent connections:", server.connections); }); connection.on("error", function(e) { - util.log("local error: " + e); + console.log("local error: " + e); if (req) { req.abort(); } if (remote) { remote.destroy(); } - return util.log("concurrent connections: " + server.connections); + return console.log("concurrent connections:", server.connections); }); connection.on("drain", function() { if (remote && stage === 5) { @@ -252,13 +252,15 @@ }); }); - server.listen(PORT, function() { - return util.log("server listening at port " + PORT); + server.listen(PORT, LOCAL_ADDRESS, function() { + var address; + address = server.address(); + return console.log("server listening at", address); }); server.on("error", function(e) { if (e.code === "EADDRINUSE") { - util.log("Address in use, aborting"); + console.log("Address in use, aborting"); } return process.exit(1); }); diff --git a/merge_sort.js b/merge_sort.js index 6701609f..3ff5bd61 100644 --- a/merge_sort.js +++ b/merge_sort.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.7.1 +// Generated by CoffeeScript 1.8.0 (function() { var merge, merge_sort; diff --git a/package.json b/package.json index a41eb460..03fc9fee 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,7 @@ { "name": "shadowsocks-heroku", - "version": "0.9.6", - "dependencies": { - }, + "version": "0.9.7", + "dependencies": {}, "engines": { "node": "0.10.x" } diff --git a/server.js b/server.js index 993bd946..31033f13 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,6 @@ -// Generated by CoffeeScript 1.7.1 +// Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, KEY, METHOD, PORT, args, config, configContent, configFile, configFromArgs, fs, http, inetAton, inetNtoa, k, net, path, portPassword, server, timeout, v; + var Encryptor, KEY, METHOD, PORT, args, config, configContent, configFile, configFromArgs, fs, http, inetAton, inetNtoa, k, net, path, server, timeout, v; net = require("net"); @@ -51,8 +51,6 @@ timeout = Math.floor(config.timeout * 1000); - portPassword = config.port_password; - PORT = process.env.PORT || 8080; KEY = process.env.KEY || config.password; @@ -172,7 +170,7 @@ return console.log("concurrent connections: " + server.connections); }); connection.on("error", function(e) { - console.warn("server : " + e); + console.warn("server: " + e); if (remote) { remote.destroy(); } @@ -192,7 +190,9 @@ }); server.listen(PORT, function() { - return console.log("server listening at port " + PORT); + var address; + address = server.address(); + return console.log("server listening at", address); }); server.on("error", function(e) { diff --git a/src/args.coffee b/src/args.coffee index 45c61476..91e4cfe3 100644 --- a/src/args.coffee +++ b/src/args.coffee @@ -1,13 +1,14 @@ exports.parseArgs = -> defination = + '-b': 'local_address' '-l': 'local_port' '-s': 'server' + '-r': 'remote_port' '-k': 'password', '-c': 'config_file', '-m': 'method' - result = {} nextIsValue = false lastKey = null @@ -20,4 +21,4 @@ exports.parseArgs = -> nextIsValue = true result -exports.version = "shadowsocks-heroku v0.9.6" +exports.version = "shadowsocks-heroku v0.9.7" diff --git a/src/encrypt.coffee b/src/encrypt.coffee index 342679a9..35a1b41b 100644 --- a/src/encrypt.coffee +++ b/src/encrypt.coffee @@ -19,7 +19,6 @@ # SOFTWARE. crypto = require("crypto") -util = require("util") merge_sort = require("./merge_sort").merge_sort int32Max = Math.pow(2, 32) @@ -28,7 +27,7 @@ cachedTables = {} # password: [encryptTable, decryptTable] getTable = (key) -> if cachedTables[key] return cachedTables[key] - util.log "calculating ciphers" + console.log "calculating ciphers" table = new Array(256) decrypt_table = new Array(256) md5sum = crypto.createHash("md5") @@ -55,7 +54,7 @@ getTable = (key) -> result = [table, decrypt_table] cachedTables[key] = result result - + encrypt = (table, buf) -> i = 0 @@ -63,7 +62,7 @@ encrypt = (table, buf) -> buf[i] = table[buf[i]] i++ buf - + class Encryptor constructor: (key, @method) -> @@ -72,20 +71,20 @@ class Encryptor @decipher = crypto.createDecipher @method, key else [@encryptTable, @decryptTable] = getTable(key) - + encrypt: (buf) -> if @method? result = new Buffer(@cipher.update(buf.toString('binary')), 'binary') result else encrypt @encryptTable, buf - + decrypt: (buf) -> if @method? result = new Buffer(@decipher.update(buf.toString('binary')), 'binary') result else encrypt @decryptTable, buf - + exports.Encryptor = Encryptor exports.getTable = getTable diff --git a/src/local.coffee b/src/local.coffee index d2b6170a..d94a8a3f 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -23,7 +23,6 @@ net = require("net") http = require("http") fs = require("fs") path = require("path") -util = require('util') args = require('./args') Encryptor = require("./encrypt").Encryptor @@ -49,8 +48,10 @@ configContent = fs.readFileSync(configFromArgs.config_file || path.resolve(__dir config = JSON.parse(configContent) for k, v of configFromArgs config[k] = v + SERVER = config.server REMOTE_PORT = config.remote_port || 80 +LOCAL_ADDRESS = config.local_address || '127.0.0.1' PORT = config.local_port KEY = config.password METHOD = config.method @@ -62,10 +63,9 @@ getServer = -> else SERVER - server = net.createServer((connection) -> - util.log "local connected" - util.log "concurrent connections: " + server.connections + console.log "local connected" + console.log "concurrent connections:", server.connections encryptor = new Encryptor(KEY, METHOD) stage = 0 headerLength = 0 @@ -101,14 +101,14 @@ server = net.createServer((connection) -> cmd = data[1] addrtype = data[3] unless cmd is 1 - util.log "unsupported cmd: " + cmd + console.log "unsupported cmd:", cmd reply = new Buffer("\u0005\u0007\u0000\u0001", "binary") connection.end reply return if addrtype is 3 addrLen = data[4] else unless addrtype is 1 - util.log "unsupported addrtype: " + addrtype + console.log "unsupported addrtype:", addrtype connection.end() return addrToSend = data.slice(3, 4).toString("binary") @@ -148,8 +148,8 @@ server = net.createServer((connection) -> connection.end() req.on 'upgrade', (res, conn, upgradeHead) -> remote = conn - util.log "remote got upgrade" - util.log "connecting #{remoteAddr} via #{aServer}" + console.log "remote got upgrade" + console.log "connecting #{remoteAddr} via #{aServer}" addrToSendBuf = new Buffer(addrToSend, "binary") addrToSendBuf = encryptor.encrypt addrToSendBuf remote.write addrToSendBuf @@ -168,17 +168,17 @@ server = net.createServer((connection) -> remote.pause() unless connection.write(data) remote.on "end", -> - util.log "remote disconnected" + console.log "remote disconnected" connection.end() - util.log "concurrent connections: " + server.connections + console.log "concurrent connections:", server.connections remote.on "error", (e)-> - util.log "remote #{remoteAddr}:#{remotePort} error: #{e}" + console.log "remote #{remoteAddr}:#{remotePort} error: #{e}" if stage is 4 connection.destroy() return connection.end() - util.log "concurrent connections: " + server.connections + console.log "concurrent connections:", server.connections remote.on "drain", -> connection.resume() @@ -195,36 +195,38 @@ server = net.createServer((connection) -> stage = 4 catch e # may encounter index out of range - util.log e + console.log e connection.destroy() - remote.destroy() if remote - else cachedPieces.push data if stage is 4 + remote.destroy() if remote + else cachedPieces.push data if stage is 4 # remote server not connected # cache received buffers # make sure no data is lost connection.on "end", -> - remote.destroy() if remote - util.log "concurrent connections: " + server.connections + remote.destroy() if remote + console.log "concurrent connections:", server.connections connection.on "error", (e)-> - util.log "local error: #{e}" + console.log "local error: #{e}" req.abort() if req - remote.destroy() if remote - util.log "concurrent connections: " + server.connections + remote.destroy() if remote + console.log "concurrent connections:", server.connections connection.on "drain", -> # calling resume() when remote not is connected will crash node.js - remote.resume() if remote and stage is 5 + remote.resume() if remote and stage is 5 connection.setTimeout timeout, -> req.abort() if req - remote.destroy() if remote + remote.destroy() if remote connection.destroy() ) -server.listen PORT, -> - util.log "server listening at port " + PORT + +server.listen PORT, LOCAL_ADDRESS, -> + address = server.address() + console.log "server listening at", address server.on "error", (e) -> - util.log "Address in use, aborting" if e.code is "EADDRINUSE" + console.log "Address in use, aborting" if e.code is "EADDRINUSE" process.exit 1 diff --git a/src/server.coffee b/src/server.coffee index d95d3773..5066df33 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -49,7 +49,6 @@ config = JSON.parse(configContent) for k, v of configFromArgs config[k] = v timeout = Math.floor(config.timeout * 1000) -portPassword = config.port_password PORT = process.env.PORT || 8080 KEY = process.env.KEY || config.password METHOD = process.env.METHOD || config.method @@ -141,32 +140,33 @@ server.on 'upgrade', (req, connection, head) -> # may encouter index out of range console.warn e connection.destroy() - remote.destroy() if remote - else cachedPieces.push data if stage is 4 + remote.destroy() if remote + else cachedPieces.push data if stage is 4 # remote server not connected # cache received buffers # make sure no data is lost connection.on "end", -> console.log "server disconnected" - remote.destroy() if remote + remote.destroy() if remote console.log "concurrent connections: " + server.connections connection.on "error", (e)-> - console.warn "server : #{e}" - remote.destroy() if remote + console.warn "server: #{e}" + remote.destroy() if remote console.log "concurrent connections: " + server.connections connection.on "drain", -> - remote.resume() if remote + remote.resume() if remote connection.setTimeout timeout, -> - remote.destroy() if remote + remote.destroy() if remote connection.destroy() server.listen PORT, -> - console.log "server listening at port " + PORT + address = server.address() + console.log "server listening at", address server.on "error", (e) -> - console.warn "Address in use, aborting" if e.code is "EADDRINUSE" + console.warn "Address in use, aborting" if e.code is "EADDRINUSE" process.exit 1 diff --git a/test.js b/test.js index c5d2a266..2ed579ec 100644 --- a/test.js +++ b/test.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.7.1 +// Generated by CoffeeScript 1.8.0 (function() { var child_process, curlRunning, encrypt, i, local, localReady, runCurl, server, serverReady, tables, target; From b4d30f6ea2acbb3ea8f92e228d79c177a5b0859f Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 25 Dec 2014 14:05:26 +0800 Subject: [PATCH 06/76] connections property is deprecated. Use getConnections() method --- local.js | 21 +++++++++++++++------ server.js | 22 ++++++++++++++++------ src/local.coffee | 28 ++++++++++++++++++---------- src/server.coffee | 28 +++++++++++++++++++--------- 4 files changed, 68 insertions(+), 31 deletions(-) diff --git a/local.js b/local.js index 672f8b6d..d5315b5f 100644 --- a/local.js +++ b/local.js @@ -72,7 +72,9 @@ server = net.createServer(function(connection) { var aServer, addrLen, addrToSend, cachedPieces, encryptor, headerLength, remote, remoteAddr, remotePort, req, stage; console.log("local connected"); - console.log("concurrent connections:", server.connections); + server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); encryptor = new Encryptor(KEY, METHOD); stage = 0; headerLength = 0; @@ -134,7 +136,6 @@ buf.write("\u0000\u0000\u0000\u0000", 4, 4, "binary"); buf.writeInt16BE(remotePort, 8); connection.write(buf); - console.log(REMOTE_PORT); req = http.request({ host: aServer, port: REMOTE_PORT, @@ -180,7 +181,9 @@ remote.on("end", function() { console.log("remote disconnected"); connection.end(); - return console.log("concurrent connections:", server.connections); + return server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); }); remote.on("error", function(e) { console.log("remote " + remoteAddr + ":" + remotePort + " error: " + e); @@ -189,7 +192,9 @@ return; } connection.end(); - return console.log("concurrent connections:", server.connections); + return server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); }); remote.on("drain", function() { return connection.resume(); @@ -224,7 +229,9 @@ if (remote) { remote.destroy(); } - return console.log("concurrent connections:", server.connections); + return server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); }); connection.on("error", function(e) { console.log("local error: " + e); @@ -234,7 +241,9 @@ if (remote) { remote.destroy(); } - return console.log("concurrent connections:", server.connections); + return server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); }); connection.on("drain", function() { if (remote && stage === 5) { diff --git a/server.js b/server.js index 31033f13..7cea7138 100644 --- a/server.js +++ b/server.js @@ -68,7 +68,9 @@ var addrLen, cachedPieces, encryptor, headerLength, remote, remoteAddr, remotePort, stage; connection.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' + 'Upgrade: WebSocket\r\n' + 'Connection: Upgrade\r\n' + '\r\n'); console.log("server connected"); - console.log("concurrent connections: " + server.connections); + server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); encryptor = new Encryptor(KEY, METHOD); stage = 0; headerLength = 0; @@ -108,7 +110,7 @@ console.log(remoteAddr); remote = net.connect(remotePort, remoteAddr, function() { var i, piece; - console.log("connecting " + remoteAddr); + console.log("connecting", remoteAddr); i = 0; while (i < cachedPieces.length) { piece = cachedPieces[i]; @@ -126,13 +128,17 @@ }); remote.on("end", function() { console.log("remote disconnected"); - console.log("concurrent connections: " + server.connections); + server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); return connection.end(); }); remote.on("error", function(e) { console.log("remote : " + e); connection.destroy(); - return console.log("concurrent connections: " + server.connections); + return server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); }); remote.on("drain", function() { return connection.resume(); @@ -167,14 +173,18 @@ if (remote) { remote.destroy(); } - return console.log("concurrent connections: " + server.connections); + return server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); }); connection.on("error", function(e) { console.warn("server: " + e); if (remote) { remote.destroy(); } - return console.log("concurrent connections: " + server.connections); + return server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); }); connection.on("drain", function() { if (remote) { diff --git a/src/local.coffee b/src/local.coffee index d94a8a3f..9fbc9d99 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -18,7 +18,6 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. - net = require("net") http = require("http") fs = require("fs") @@ -26,7 +25,7 @@ path = require("path") args = require('./args') Encryptor = require("./encrypt").Encryptor -console.log(args.version) +console.log args.version inetNtoa = (buf) -> buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3] @@ -65,7 +64,9 @@ getServer = -> server = net.createServer((connection) -> console.log "local connected" - console.log "concurrent connections:", server.connections + server.getConnections (err, count) -> + console.log "concurrent connections:", count + return encryptor = new Encryptor(KEY, METHOD) stage = 0 headerLength = 0 @@ -81,7 +82,7 @@ server = net.createServer((connection) -> if stage is 5 # pipe sockets data = encryptor.encrypt data - connection.pause() unless remote.write(data) + connection.pause() unless remote.write(data) return if stage is 0 tempBuf = new Buffer(2) @@ -129,7 +130,6 @@ server = net.createServer((connection) -> buf.writeInt16BE remotePort, 8 connection.write buf # connect remote server - console.log REMOTE_PORT req = http.request( host: aServer, port: REMOTE_PORT, @@ -165,12 +165,14 @@ server = net.createServer((connection) -> remote.on "data", (data) -> data = encryptor.decrypt data - remote.pause() unless connection.write(data) + remote.pause() unless connection.write(data) remote.on "end", -> console.log "remote disconnected" connection.end() - console.log "concurrent connections:", server.connections + server.getConnections (err, count) -> + console.log "concurrent connections:", count + return remote.on "error", (e)-> console.log "remote #{remoteAddr}:#{remotePort} error: #{e}" @@ -178,7 +180,9 @@ server = net.createServer((connection) -> connection.destroy() return connection.end() - console.log "concurrent connections:", server.connections + server.getConnections (err, count) -> + console.log "concurrent connections:", count + return remote.on "drain", -> connection.resume() @@ -205,13 +209,17 @@ server = net.createServer((connection) -> connection.on "end", -> remote.destroy() if remote - console.log "concurrent connections:", server.connections + server.getConnections (err, count) -> + console.log "concurrent connections:", count + return connection.on "error", (e)-> console.log "local error: #{e}" req.abort() if req remote.destroy() if remote - console.log "concurrent connections:", server.connections + server.getConnections (err, count) -> + console.log "concurrent connections:", count + return connection.on "drain", -> # calling resume() when remote not is connected will crash node.js diff --git a/src/server.coffee b/src/server.coffee index 5066df33..dea8c9cf 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -25,7 +25,7 @@ http = require("http") args = require("./args") Encryptor = require("./encrypt").Encryptor -console.log(args.version) +console.log args.version inetNtoa = (buf) -> buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3] @@ -63,7 +63,9 @@ server.on 'upgrade', (req, connection, head) -> 'Connection: Upgrade\r\n' + '\r\n' console.log "server connected" - console.log "concurrent connections: " + server.connections + server.getConnections (err, count) -> + console.log "concurrent connections:", count + return encryptor = new Encryptor(KEY, METHOD) stage = 0 headerLength = 0 @@ -75,7 +77,7 @@ server.on 'upgrade', (req, connection, head) -> connection.on "data", (data) -> data = encryptor.decrypt data if stage is 5 - connection.pause() unless remote.write(data) + connection.pause() unless remote.write(data) return if stage is 0 try @@ -98,7 +100,7 @@ server.on 'upgrade', (req, connection, head) -> console.log remoteAddr # connect remote server remote = net.connect(remotePort, remoteAddr, -> - console.log "connecting " + remoteAddr + console.log "connecting", remoteAddr i = 0 while i < cachedPieces.length @@ -110,17 +112,21 @@ server.on 'upgrade', (req, connection, head) -> ) remote.on "data", (data) -> data = encryptor.encrypt data - remote.pause() unless connection.write(data) + remote.pause() unless connection.write(data) remote.on "end", -> console.log "remote disconnected" - console.log "concurrent connections: " + server.connections + server.getConnections (err, count) -> + console.log "concurrent connections:", count + return connection.end() remote.on "error", (e)-> console.log "remote : #{e}" connection.destroy() - console.log "concurrent connections: " + server.connections + server.getConnections (err, count) -> + console.log "concurrent connections:", count + return remote.on "drain", -> connection.resume() @@ -149,12 +155,16 @@ server.on 'upgrade', (req, connection, head) -> connection.on "end", -> console.log "server disconnected" remote.destroy() if remote - console.log "concurrent connections: " + server.connections + server.getConnections (err, count) -> + console.log "concurrent connections:", count + return connection.on "error", (e)-> console.warn "server: #{e}" remote.destroy() if remote - console.log "concurrent connections: " + server.connections + server.getConnections (err, count) -> + console.log "concurrent connections:", count + return connection.on "drain", -> remote.resume() if remote From cdda58527ff9553a32ee89f478e072ed3bb35b5f Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 25 Dec 2014 14:46:50 +0800 Subject: [PATCH 07/76] Support pass multiple `server` options from command line arguments. --- README.md | 31 +++++++++++++++++-------------- args.js | 17 ++++++++++++----- config.json | 12 +++++++----- local.js | 18 +----------------- server.js | 18 +----------------- src/args.coffee | 14 +++++++++----- src/local.coffee | 12 ------------ src/server.coffee | 12 ------------ src/test.coffee | 1 - test/config.json | 8 -------- 10 files changed, 47 insertions(+), 96 deletions(-) delete mode 100644 test/config.json diff --git a/README.md b/README.md index 3682b235..fec8361e 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,22 @@ shadowsocks-heroku ================== -shadowsocks-heroku is a lightweight tunnel proxy which can help you get through - firewalls. It is a port of [shadowsocks](https://github.com/clowwindy/shadowsocks), but - through a different protocol. +shadowsocks-heroku is a lightweight tunnel proxy which can help you get through firewalls. It is a port of [shadowsocks](https://github.com/clowwindy/shadowsocks), but through a different protocol. -shadowsocks-heroku uses WebSockets instead of raw sockets, - so it can be deployed on [heroku](https://www.heroku.com/). +shadowsocks-heroku uses WebSocket instead of raw sockets, so it can be deployed on [Heroku](https://www.heroku.com/). Notice that the protocol is INCOMPATIBLE with the origin shadowsocks. Usage ----- - $ heroku create - Creating still-tor-8707... done, stack is cedar - http://still-tor-8707.herokuapp.com/ | git@heroku.com:still-tor-8707.git +``` +$ heroku create +Creating still-tor-8707... done, stack is cedar +http://still-tor-8707.herokuapp.com/ | git@heroku.com:still-tor-8707.git +``` -Push the code to heroku. +Push the code to Heroku. ``` $ git push heroku master @@ -30,12 +29,12 @@ Total 178 (delta 89), reused 162 (delta 78) -----> Node.js app detected -----> Requested node range: 0.10.x ------> Resolved node version: 0.10.26 +-----> Resolved node version: 0.10.33 -----> Downloading and installing node -----> Writing a custom .npmrc to circumvent npm bugs -----> Exporting config vars to environment -----> Installing dependencies - npm WARN package.json shadowsocks-heroku@0.9.6 No repository field. + npm WARN package.json shadowsocks-heroku@0.9.7 No repository field. -----> Cleaning up node-gyp and npm artifacts -----> Building runtime environment -----> Discovering process types @@ -67,11 +66,15 @@ shadowsocks-heroku v0.9.6 Change proxy settings of your browser into: - SOCKS5 127.0.0.1:1080 +``` +SOCKS5 127.0.0.1:1080 +``` Troubleshooting ----------------- +--------------- If there is something wrong, you can check the logs by: - $ heroku logs -t --app still-tor-8707 +``` +$ heroku logs -t --app still-tor-8707 +``` diff --git a/args.js b/args.js index 9c1633cf..c7812251 100644 --- a/args.js +++ b/args.js @@ -1,8 +1,8 @@ // Generated by CoffeeScript 1.8.0 (function() { exports.parseArgs = function() { - var defination, lastKey, nextIsValue, oneArg, result, _, _ref; - defination = { + var lastKey, nextIsValue, oneArg, options, result, _, _ref; + options = { '-b': 'local_address', '-l': 'local_port', '-s': 'server', @@ -18,10 +18,17 @@ for (_ in _ref) { oneArg = _ref[_]; if (nextIsValue) { - result[lastKey] = oneArg; + if (result[lastKey]) { + if (!(result[lastKey] instanceof Array)) { + result[lastKey] = [result[lastKey]]; + } + result[lastKey].push(oneArg); + } else { + result[lastKey] = oneArg; + } nextIsValue = false; - } else if (oneArg in defination) { - lastKey = defination[oneArg]; + } else if (oneArg in options) { + lastKey = options[oneArg]; nextIsValue = true; } } diff --git a/config.json b/config.json index d78679ca..8db54f6b 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,9 @@ { - "server": ["still-tor-8707.herokuapp.com"], - "local_port": 1080, - "password": "`try*(^^$some^$%^complex>:<>?~password/", - "timeout": 600, - "method": "rc4" + "server": [ + "still-tor-8707.herokuapp.com" + ], + "local_port": 1080, + "password": "`try*(^^$some^$%^complex>:<>?~password/", + "timeout": 600, + "method": "rc4" } diff --git a/local.js b/local.js index d5315b5f..d36fb0da 100644 --- a/local.js +++ b/local.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SERVER, args, config, configContent, configFromArgs, fs, getServer, http, inetAton, inetNtoa, k, net, path, server, timeout, v; + var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SERVER, args, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, path, server, timeout, v; net = require("net"); @@ -20,22 +20,6 @@ return buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3]; }; - inetAton = function(ipStr) { - var buf, i, parts; - parts = ipStr.split("."); - if (parts.length !== 4) { - return null; - } else { - buf = new Buffer(4); - i = 0; - while (i < 4) { - buf[i] = +parts[i]; - i++; - } - return buf; - } - }; - configFromArgs = args.parseArgs(); configContent = fs.readFileSync(configFromArgs.config_file || path.resolve(__dirname, "config.json")); diff --git a/server.js b/server.js index 7cea7138..dcc5b142 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, KEY, METHOD, PORT, args, config, configContent, configFile, configFromArgs, fs, http, inetAton, inetNtoa, k, net, path, server, timeout, v; + var Encryptor, KEY, METHOD, PORT, args, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, path, server, timeout, v; net = require("net"); @@ -20,22 +20,6 @@ return buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3]; }; - inetAton = function(ipStr) { - var buf, i, parts; - parts = ipStr.split("."); - if (parts.length !== 4) { - return null; - } else { - buf = new Buffer(4); - i = 0; - while (i < 4) { - buf[i] = +parts[i]; - i++; - } - return buf; - } - }; - configFromArgs = args.parseArgs(); configFile = configFromArgs.config_file || path.resolve(__dirname, "config.json"); diff --git a/src/args.coffee b/src/args.coffee index 91e4cfe3..7a7ca2ff 100644 --- a/src/args.coffee +++ b/src/args.coffee @@ -1,6 +1,5 @@ - exports.parseArgs = -> - defination = + options = '-b': 'local_address' '-l': 'local_port' '-s': 'server' @@ -14,10 +13,15 @@ exports.parseArgs = -> lastKey = null for _, oneArg of process.argv if nextIsValue - result[lastKey] = oneArg + if result[lastKey] + if result[lastKey] not instanceof Array + result[lastKey] = [result[lastKey]] + result[lastKey].push oneArg + else + result[lastKey] = oneArg nextIsValue = false - else if oneArg of defination - lastKey = defination[oneArg] + else if oneArg of options + lastKey = options[oneArg] nextIsValue = true result diff --git a/src/local.coffee b/src/local.coffee index 9fbc9d99..ea579719 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -29,18 +29,6 @@ console.log args.version inetNtoa = (buf) -> buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3] -inetAton = (ipStr) -> - parts = ipStr.split(".") - unless parts.length is 4 - null - else - buf = new Buffer(4) - i = 0 - - while i < 4 - buf[i] = +parts[i] - i++ - buf configFromArgs = args.parseArgs() configContent = fs.readFileSync(configFromArgs.config_file || path.resolve(__dirname, "config.json")) diff --git a/src/server.coffee b/src/server.coffee index dea8c9cf..727bb38d 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -29,18 +29,6 @@ console.log args.version inetNtoa = (buf) -> buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3] -inetAton = (ipStr) -> - parts = ipStr.split(".") - unless parts.length is 4 - null - else - buf = new Buffer(4) - i = 0 - - while i < 4 - buf[i] = +parts[i] - i++ - buf configFromArgs = args.parseArgs() configFile = configFromArgs.config_file or path.resolve(__dirname, "config.json") diff --git a/src/test.coffee b/src/test.coffee index d629a597..55768982 100644 --- a/src/test.coffee +++ b/src/test.coffee @@ -73,4 +73,3 @@ server.stdout.on 'data', (data) -> serverReady = true if localReady and serverReady and not curlRunning runCurl() - diff --git a/test/config.json b/test/config.json deleted file mode 100644 index 4870dbe4..00000000 --- a/test/config.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "server":"localhost", - "local_port":1080, - "remote_port":8080, - "password":"`try*(^^$some^$%^complex>:<>?~password/", - "timeout":600, - "method":null -} From afcd1a2ce4649e3f9b246a9b734d1bd9b1b361d4 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Fri, 26 Dec 2014 03:11:58 +0800 Subject: [PATCH 08/76] Use `minimist` to parse arguments. --- .gitignore | 27 +++++++++++++++++++++++++++ args.js | 40 ---------------------------------------- local.js | 31 ++++++++++++++++++++++++------- package.json | 4 +++- server.js | 30 ++++++++++++++++++++++-------- src/args.coffee | 28 ---------------------------- src/local.coffee | 27 +++++++++++++++++++++------ src/server.coffee | 25 ++++++++++++++++++------- 8 files changed, 115 insertions(+), 97 deletions(-) create mode 100644 .gitignore delete mode 100644 args.js delete mode 100644 src/args.coffee diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..d1d5c6dd --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- +node_modules diff --git a/args.js b/args.js deleted file mode 100644 index c7812251..00000000 --- a/args.js +++ /dev/null @@ -1,40 +0,0 @@ -// Generated by CoffeeScript 1.8.0 -(function() { - exports.parseArgs = function() { - var lastKey, nextIsValue, oneArg, options, result, _, _ref; - options = { - '-b': 'local_address', - '-l': 'local_port', - '-s': 'server', - '-r': 'remote_port', - '-k': 'password', - '-c': 'config_file', - '-m': 'method' - }; - result = {}; - nextIsValue = false; - lastKey = null; - _ref = process.argv; - for (_ in _ref) { - oneArg = _ref[_]; - if (nextIsValue) { - if (result[lastKey]) { - if (!(result[lastKey] instanceof Array)) { - result[lastKey] = [result[lastKey]]; - } - result[lastKey].push(oneArg); - } else { - result[lastKey] = oneArg; - } - nextIsValue = false; - } else if (oneArg in options) { - lastKey = options[oneArg]; - nextIsValue = true; - } - } - return result; - }; - - exports.version = "shadowsocks-heroku v0.9.7"; - -}).call(this); diff --git a/local.js b/local.js index d36fb0da..5cd6a151 100644 --- a/local.js +++ b/local.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SERVER, args, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, path, server, timeout, v; + var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SERVER, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, server, timeout, v; net = require("net"); @@ -10,19 +10,36 @@ path = require("path"); - args = require('./args'); + parseArgs = require("minimist"); Encryptor = require("./encrypt").Encryptor; - console.log(args.version); + options = { + alias: { + 'b': 'local_address', + 'l': 'local_port', + 's': 'server', + 'r': 'remote_port', + 'k': 'password', + 'c': 'config_file', + 'm': 'method' + }, + string: ['local_address', 'server', 'password', 'config_file', 'method'], + "default": { + 'local_address': '127.0.0.1', + 'local_port': 1080, + 'remote_port': 80, + 'config_file': path.resolve(__dirname, "config.json") + } + }; inetNtoa = function(buf) { return buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3]; }; - configFromArgs = args.parseArgs(); + configFromArgs = parseArgs(process.argv.slice(2), options); - configContent = fs.readFileSync(configFromArgs.config_file || path.resolve(__dirname, "config.json")); + configContent = fs.readFileSync(configFromArgs.config_file); config = JSON.parse(configContent); @@ -33,9 +50,9 @@ SERVER = config.server; - REMOTE_PORT = config.remote_port || 80; + REMOTE_PORT = config.remote_port; - LOCAL_ADDRESS = config.local_address || '127.0.0.1'; + LOCAL_ADDRESS = config.local_address; PORT = config.local_port; diff --git a/package.json b/package.json index 03fc9fee..747448e4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,9 @@ { "name": "shadowsocks-heroku", "version": "0.9.7", - "dependencies": {}, + "dependencies": { + "minimist": "^1.1.0" + }, "engines": { "node": "0.10.x" } diff --git a/server.js b/server.js index dcc5b142..656be0dd 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, KEY, METHOD, PORT, args, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, path, server, timeout, v; + var Encryptor, KEY, METHOD, PORT, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, server, timeout, v; net = require("net"); @@ -10,19 +10,33 @@ http = require("http"); - args = require("./args"); + parseArgs = require("minimist"); Encryptor = require("./encrypt").Encryptor; - console.log(args.version); + options = { + alias: { + 'r': 'remote_port', + 'k': 'password', + 'c': 'config_file', + 'm': 'method' + }, + string: ['password', 'method', 'config_file'], + "default": { + 'remote_port': process.env.PORT || 8080, + 'password': process.env.KEY, + 'method': process.env.METHOD, + 'config_file': path.resolve(__dirname, "config.json") + } + }; inetNtoa = function(buf) { return buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3]; }; - configFromArgs = args.parseArgs(); + configFromArgs = parseArgs(process.argv.slice(2), options); - configFile = configFromArgs.config_file || path.resolve(__dirname, "config.json"); + configFile = configFromArgs.config_file; configContent = fs.readFileSync(configFile); @@ -35,11 +49,11 @@ timeout = Math.floor(config.timeout * 1000); - PORT = process.env.PORT || 8080; + PORT = config.remote_port; - KEY = process.env.KEY || config.password; + KEY = config.password; - METHOD = process.env.METHOD || config.method; + METHOD = config.method; server = http.createServer(function(req, res) { res.writeHead(200, { diff --git a/src/args.coffee b/src/args.coffee deleted file mode 100644 index 7a7ca2ff..00000000 --- a/src/args.coffee +++ /dev/null @@ -1,28 +0,0 @@ -exports.parseArgs = -> - options = - '-b': 'local_address' - '-l': 'local_port' - '-s': 'server' - '-r': 'remote_port' - '-k': 'password', - '-c': 'config_file', - '-m': 'method' - - result = {} - nextIsValue = false - lastKey = null - for _, oneArg of process.argv - if nextIsValue - if result[lastKey] - if result[lastKey] not instanceof Array - result[lastKey] = [result[lastKey]] - result[lastKey].push oneArg - else - result[lastKey] = oneArg - nextIsValue = false - else if oneArg of options - lastKey = options[oneArg] - nextIsValue = true - result - -exports.version = "shadowsocks-heroku v0.9.7" diff --git a/src/local.coffee b/src/local.coffee index ea579719..15fc0575 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -22,23 +22,38 @@ net = require("net") http = require("http") fs = require("fs") path = require("path") -args = require('./args') +parseArgs = require("minimist") Encryptor = require("./encrypt").Encryptor -console.log args.version +options = + alias: + 'b': 'local_address' + 'l': 'local_port' + 's': 'server' + 'r': 'remote_port' + 'k': 'password', + 'c': 'config_file', + 'm': 'method' + string: ['local_address', 'server', 'password', + 'config_file', 'method'] + default: + 'local_address': '127.0.0.1' + 'local_port': 1080 + 'remote_port': 80 + 'config_file': path.resolve(__dirname, "config.json") inetNtoa = (buf) -> buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3] -configFromArgs = args.parseArgs() -configContent = fs.readFileSync(configFromArgs.config_file || path.resolve(__dirname, "config.json")) +configFromArgs = parseArgs process.argv.slice(2), options +configContent = fs.readFileSync(configFromArgs.config_file) config = JSON.parse(configContent) for k, v of configFromArgs config[k] = v SERVER = config.server -REMOTE_PORT = config.remote_port || 80 -LOCAL_ADDRESS = config.local_address || '127.0.0.1' +REMOTE_PORT = config.remote_port +LOCAL_ADDRESS = config.local_address PORT = config.local_port KEY = config.password METHOD = config.method diff --git a/src/server.coffee b/src/server.coffee index 727bb38d..c33bad66 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -22,24 +22,35 @@ net = require("net") fs = require("fs") path = require("path") http = require("http") -args = require("./args") +parseArgs = require("minimist") Encryptor = require("./encrypt").Encryptor -console.log args.version +options = + alias: + 'r': 'remote_port' + 'k': 'password', + 'c': 'config_file', + 'm': 'method' + string: ['password', 'method', 'config_file'] + default: + 'remote_port': process.env.PORT || 8080 + 'password': process.env.KEY + 'method': process.env.METHOD + 'config_file': path.resolve(__dirname, "config.json") inetNtoa = (buf) -> buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3] -configFromArgs = args.parseArgs() -configFile = configFromArgs.config_file or path.resolve(__dirname, "config.json") +configFromArgs = parseArgs process.argv.slice(2), options +configFile = configFromArgs.config_file configContent = fs.readFileSync(configFile) config = JSON.parse(configContent) for k, v of configFromArgs config[k] = v timeout = Math.floor(config.timeout * 1000) -PORT = process.env.PORT || 8080 -KEY = process.env.KEY || config.password -METHOD = process.env.METHOD || config.method +PORT = config.remote_port +KEY = config.password +METHOD = config.method server = http.createServer (req, res) -> res.writeHead 200, 'Content-Type':'text/plain' From dcfb8ab2f5f93d4ecd39cb4047bc3c9547d52d8f Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Fri, 26 Dec 2014 03:26:26 +0800 Subject: [PATCH 09/76] Added LICENSE --- LICENSE | 21 +++++++++++++++++++++ src/encrypt.coffee | 20 -------------------- src/local.coffee | 20 -------------------- src/merge_sort.coffee | 20 -------------------- src/server.coffee | 20 -------------------- web.js | 22 ---------------------- 6 files changed, 21 insertions(+), 102 deletions(-) create mode 100644 LICENSE delete mode 100644 web.js diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..a2487bee --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) +Copyright (c) 2014 Zhao Xiaohong +Copyright (c) 2012 clowwindy + +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: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +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. diff --git a/src/encrypt.coffee b/src/encrypt.coffee index 35a1b41b..21dcdbbc 100644 --- a/src/encrypt.coffee +++ b/src/encrypt.coffee @@ -1,23 +1,3 @@ -# Copyright (c) 2012 clowwindy -# -# 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: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# 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. - crypto = require("crypto") merge_sort = require("./merge_sort").merge_sort int32Max = Math.pow(2, 32) diff --git a/src/local.coffee b/src/local.coffee index 15fc0575..bcb3ba79 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -1,23 +1,3 @@ -# Copyright (c) 2012 clowwindy -# -# 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: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# 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. - net = require("net") http = require("http") fs = require("fs") diff --git a/src/merge_sort.coffee b/src/merge_sort.coffee index 1733e984..b6b20d90 100644 --- a/src/merge_sort.coffee +++ b/src/merge_sort.coffee @@ -1,23 +1,3 @@ -# Copyright (c) 2012 clowwindy -# -# 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: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# 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. - merge = (left, right, comparison) -> result = new Array() while (left.length > 0) and (right.length > 0) diff --git a/src/server.coffee b/src/server.coffee index c33bad66..31f59a84 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -1,23 +1,3 @@ -# Copyright (c) 2012 clowwindy -# -# 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: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# 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. - net = require("net") fs = require("fs") path = require("path") diff --git a/web.js b/web.js deleted file mode 100644 index ae74d48d..00000000 --- a/web.js +++ /dev/null @@ -1,22 +0,0 @@ -net = require("net"); - -PORT = process.env.PORT || 5000; -server = net.createServer(function (connection) { - connection.write('HTTP/1.1 200 OK\r\nContent-Type:text/plain\r\n\r\nd\r\nHello world!\n\r\n'); - setTimeout(function () { - connection.write('6\r\nOver!\n\r\n0\r\n'); - connection.end(); - }, 5000); - - connection.on("error", function (e) { - }); -}); -server.listen(PORT, function () { - return console.log("server listening at port " + PORT); -}); - -server.on("error", function (e) { - if (e.code === "EADDRINUSE") { - return console.warn("Address in use, aborting"); - } -}); From 6519b6b80bae633bcf5a6149a3f1f68f500308d0 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Mon, 5 Jan 2015 16:18:20 +0800 Subject: [PATCH 10/76] Use `ws` to handle the WebSocket heavy lifting ws: https://github.com/einaros/ws --- README.md | 34 +++++------- config.json | 2 +- local.js | 124 ++++++++++++++---------------------------- package.json | 5 +- server.js | 100 ++++++++++------------------------ src/encrypt.coffee | 1 - src/local.coffee | 93 ++++++++++--------------------- src/merge_sort.coffee | 6 +- src/server.coffee | 72 +++++++----------------- 9 files changed, 138 insertions(+), 299 deletions(-) diff --git a/README.md b/README.md index fec8361e..3befa4dd 100644 --- a/README.md +++ b/README.md @@ -20,26 +20,7 @@ Push the code to Heroku. ``` $ git push heroku master -Initializing repository, done. -Counting objects: 178, done. -Delta compression using up to 4 threads. -Compressing objects: 100% (97/97), done. -Writing objects: 100% (178/178), 47.42 KiB | 0 bytes/s, done. -Total 178 (delta 89), reused 162 (delta 78) - ------> Node.js app detected ------> Requested node range: 0.10.x ------> Resolved node version: 0.10.33 ------> Downloading and installing node ------> Writing a custom .npmrc to circumvent npm bugs ------> Exporting config vars to environment ------> Installing dependencies - npm WARN package.json shadowsocks-heroku@0.9.7 No repository field. ------> Cleaning up node-gyp and npm artifacts ------> Building runtime environment ------> Discovering process types - Procfile declares types -> web - +… -----> Compressing... done, 5.1MB -----> Launching... done, v3 http://still-tor-8707.herokuapp.com/ deployed to Heroku @@ -57,6 +38,19 @@ KEY: foobar METHOD: rc4 ``` +Install project dependencies with `npm install`: + +``` +$ npm install +… +minimist@1.1.0 node_modules/minimist + +ws@0.6.4 node_modules/ws +├── options@0.0.6 +├── ultron@1.0.1 +└── nan@1.4.1 +``` + Then run: ``` diff --git a/config.json b/config.json index 8db54f6b..56373b86 100644 --- a/config.json +++ b/config.json @@ -4,6 +4,6 @@ ], "local_port": 1080, "password": "`try*(^^$some^$%^complex>:<>?~password/", - "timeout": 600, + "timeout": 50, "method": "rc4" } diff --git a/local.js b/local.js index 5cd6a151..004c3ff8 100644 --- a/local.js +++ b/local.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SERVER, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, server, timeout, v; + var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SERVER, WebSocket, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, server, timeout, v; net = require("net"); @@ -10,6 +10,8 @@ path = require("path"); + WebSocket = require('ws'); + parseArgs = require("minimist"); Encryptor = require("./encrypt").Encryptor; @@ -71,7 +73,7 @@ }; server = net.createServer(function(connection) { - var aServer, addrLen, addrToSend, cachedPieces, encryptor, headerLength, remote, remoteAddr, remotePort, req, stage; + var aServer, addrLen, addrToSend, cachedPieces, encryptor, headerLength, remoteAddr, remotePort, stage, ws; console.log("local connected"); server.getConnections(function(err, count) { console.log("concurrent connections:", count); @@ -79,10 +81,9 @@ encryptor = new Encryptor(KEY, METHOD); stage = 0; headerLength = 0; - remote = null; - req = null; cachedPieces = []; addrLen = 0; + ws = null; remoteAddr = null; remotePort = null; addrToSend = ""; @@ -91,9 +92,9 @@ var addrtype, buf, cmd, e, reply, tempBuf; if (stage === 5) { data = encryptor.encrypt(data); - if (!remote.write(data)) { - connection.pause(); - } + ws.send(data, { + binary: true + }); return; } if (stage === 0) { @@ -137,72 +138,40 @@ buf.write("\u0000\u0000\u0000\u0000", 4, 4, "binary"); buf.writeInt16BE(remotePort, 8); connection.write(buf); - req = http.request({ - host: aServer, - port: REMOTE_PORT, - headers: { - 'Connection': 'Upgrade', - 'Upgrade': 'websocket' - } - }); - req.setNoDelay(true); - req.end(); - req.setTimeout(timeout, function() { - req.abort(); - return connection.end(); - }); - req.on('error', function(e) { - console.warn("req " + e); - req.abort(); - return connection.end(); - }); - req.on('upgrade', function(res, conn, upgradeHead) { + ws = new WebSocket("ws://" + aServer + ":" + REMOTE_PORT + "/"); + ws.on("open", function() { var addrToSendBuf, i, piece; - remote = conn; - console.log("remote got upgrade"); console.log("connecting " + remoteAddr + " via " + aServer); addrToSendBuf = new Buffer(addrToSend, "binary"); addrToSendBuf = encryptor.encrypt(addrToSendBuf); - remote.write(addrToSendBuf); + ws.send(addrToSendBuf, { + binary: true + }); i = 0; while (i < cachedPieces.length) { piece = cachedPieces[i]; piece = encryptor.encrypt(piece); - remote.write(piece); + ws.send(piece, { + binary: true + }); i++; } cachedPieces = null; - stage = 5; - remote.on("data", function(data) { - data = encryptor.decrypt(data); - if (!connection.write(data)) { - return remote.pause(); - } - }); - remote.on("end", function() { - console.log("remote disconnected"); - connection.end(); - return server.getConnections(function(err, count) { - console.log("concurrent connections:", count); - }); - }); - remote.on("error", function(e) { - console.log("remote " + remoteAddr + ":" + remotePort + " error: " + e); - if (stage === 4) { - connection.destroy(); - return; - } - connection.end(); - return server.getConnections(function(err, count) { - console.log("concurrent connections:", count); - }); - }); - remote.on("drain", function() { - return connection.resume(); - }); - return remote.setTimeout(timeout, function() { - connection.end(); - return remote.destroy(); + return stage = 5; + }); + ws.on("message", function(data, flags) { + data = encryptor.decrypt(data); + return connection.write(data); + }); + ws.on("close", function() { + console.log("remote disconnected"); + return connection.destroy(); + }); + ws.on("error", function(e) { + console.log("remote " + remoteAddr + ":" + remotePort + " error: " + e); + connection.destroy(); + return server.getConnections(function(err, count) { + console.log("concurrent connections:", count); }); }); if (data.length > headerLength) { @@ -215,10 +184,7 @@ } catch (_error) { e = _error; console.log(e); - connection.destroy(); - if (remote) { - return remote.destroy(); - } + return connection.destroy(); } } else { if (stage === 4) { @@ -227,8 +193,9 @@ } }); connection.on("end", function() { - if (remote) { - remote.destroy(); + console.log("local disconnected"); + if (ws) { + ws.close(); } return server.getConnections(function(err, count) { console.log("concurrent connections:", count); @@ -236,29 +203,18 @@ }); connection.on("error", function(e) { console.log("local error: " + e); - if (req) { - req.abort(); - } - if (remote) { - remote.destroy(); + if (ws) { + ws.close(); } return server.getConnections(function(err, count) { console.log("concurrent connections:", count); }); }); - connection.on("drain", function() { - if (remote && stage === 5) { - return remote.resume(); - } - }); return connection.setTimeout(timeout, function() { - if (req) { - req.abort(); - } - if (remote) { - remote.destroy(); + connection.destroy(); + if (ws) { + return ws.close(); } - return connection.destroy(); }); }); diff --git a/package.json b/package.json index 747448e4..fbb43c2d 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,9 @@ { "name": "shadowsocks-heroku", - "version": "0.9.7", + "version": "0.9.8", "dependencies": { - "minimist": "^1.1.0" + "minimist": "^1.1.0", + "ws": "^0.6.3" }, "engines": { "node": "0.10.x" diff --git a/server.js b/server.js index 656be0dd..35986c74 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, KEY, METHOD, PORT, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, server, timeout, v; + var Encryptor, KEY, METHOD, PORT, WebSocket, WebSocketServer, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, timeout, v, wss; net = require("net"); @@ -10,6 +10,10 @@ http = require("http"); + WebSocket = require('ws'); + + WebSocketServer = WebSocket.Server; + parseArgs = require("minimist"); Encryptor = require("./encrypt").Encryptor; @@ -55,20 +59,14 @@ METHOD = config.method; - server = http.createServer(function(req, res) { - res.writeHead(200, { - 'Content-Type': 'text/plain' - }); - return res.end('Good Day!'); + wss = new WebSocketServer({ + port: PORT }); - server.on('upgrade', function(req, connection, head) { + wss.on("connection", function(ws) { var addrLen, cachedPieces, encryptor, headerLength, remote, remoteAddr, remotePort, stage; - connection.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' + 'Upgrade: WebSocket\r\n' + 'Connection: Upgrade\r\n' + '\r\n'); console.log("server connected"); - server.getConnections(function(err, count) { - console.log("concurrent connections:", count); - }); + console.log("concurrent connections:", wss.clients.length); encryptor = new Encryptor(KEY, METHOD); stage = 0; headerLength = 0; @@ -77,13 +75,11 @@ addrLen = 0; remoteAddr = null; remotePort = null; - connection.on("data", function(data) { + ws.on("message", function(data, flags) { var addrtype, buf, e; data = encryptor.decrypt(data); if (stage === 5) { - if (!remote.write(data)) { - connection.pause(); - } + remote.write(data); return; } if (stage === 0) { @@ -93,7 +89,7 @@ addrLen = data[1]; } else if (addrtype !== 1) { console.warn("unsupported addrtype: " + addrtype); - connection.end(); + ws.close(); return; } if (addrtype === 1) { @@ -105,7 +101,6 @@ remotePort = data.readUInt16BE(2 + addrLen); headerLength = 2 + addrLen + 2; } - console.log(remoteAddr); remote = net.connect(remotePort, remoteAddr, function() { var i, piece; console.log("connecting", remoteAddr); @@ -120,30 +115,23 @@ }); remote.on("data", function(data) { data = encryptor.encrypt(data); - if (!connection.write(data)) { - return remote.pause(); + if (ws.readyState === WebSocket.OPEN) { + return ws.send(data, { + binary: true + }); } }); remote.on("end", function() { - console.log("remote disconnected"); - server.getConnections(function(err, count) { - console.log("concurrent connections:", count); - }); - return connection.end(); + ws.emit("close"); + return console.log("remote disconnected"); }); remote.on("error", function(e) { - console.log("remote : " + e); - connection.destroy(); - return server.getConnections(function(err, count) { - console.log("concurrent connections:", count); - }); - }); - remote.on("drain", function() { - return connection.resume(); + ws.emit("close"); + return console.log("remote: " + e); }); remote.setTimeout(timeout, function() { - connection.end(); - return remote.destroy(); + remote.destroy(); + return ws.close(); }); if (data.length > headerLength) { buf = new Buffer(data.length - headerLength); @@ -155,10 +143,10 @@ } catch (_error) { e = _error; console.warn(e); - connection.destroy(); if (remote) { - return remote.destroy(); + remote.destroy(); } + return ws.close(); } } else { if (stage === 4) { @@ -166,48 +154,20 @@ } } }); - connection.on("end", function() { + ws.on("close", function() { console.log("server disconnected"); + console.log("concurrent connections:", wss.clients.length); if (remote) { - remote.destroy(); + return remote.destroy(); } - return server.getConnections(function(err, count) { - console.log("concurrent connections:", count); - }); }); - connection.on("error", function(e) { + return ws.on("error", function(e) { console.warn("server: " + e); + console.log("concurrent connections:", wss.clients.length); if (remote) { - remote.destroy(); - } - return server.getConnections(function(err, count) { - console.log("concurrent connections:", count); - }); - }); - connection.on("drain", function() { - if (remote) { - return remote.resume(); + return remote.destroy(); } }); - return connection.setTimeout(timeout, function() { - if (remote) { - remote.destroy(); - } - return connection.destroy(); - }); - }); - - server.listen(PORT, function() { - var address; - address = server.address(); - return console.log("server listening at", address); - }); - - server.on("error", function(e) { - if (e.code === "EADDRINUSE") { - console.warn("Address in use, aborting"); - } - return process.exit(1); }); }).call(this); diff --git a/src/encrypt.coffee b/src/encrypt.coffee index 21dcdbbc..7bee6c9c 100644 --- a/src/encrypt.coffee +++ b/src/encrypt.coffee @@ -43,7 +43,6 @@ encrypt = (table, buf) -> i++ buf - class Encryptor constructor: (key, @method) -> if @method? diff --git a/src/local.coffee b/src/local.coffee index bcb3ba79..39dc181a 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -2,6 +2,7 @@ net = require("net") http = require("http") fs = require("fs") path = require("path") +WebSocket = require('ws') parseArgs = require("minimist") Encryptor = require("./encrypt").Encryptor @@ -45,7 +46,7 @@ getServer = -> else SERVER -server = net.createServer((connection) -> +server = net.createServer (connection) -> console.log "local connected" server.getConnections (err, count) -> console.log "concurrent connections:", count @@ -53,10 +54,9 @@ server = net.createServer((connection) -> encryptor = new Encryptor(KEY, METHOD) stage = 0 headerLength = 0 - remote = null - req = null cachedPieces = [] addrLen = 0 + ws = null remoteAddr = null remotePort = null addrToSend = "" @@ -65,7 +65,7 @@ server = net.createServer((connection) -> if stage is 5 # pipe sockets data = encryptor.encrypt data - connection.pause() unless remote.write(data) + ws.send data, { binary: true } return if stage is 0 tempBuf = new Buffer(2) @@ -112,67 +112,37 @@ server = net.createServer((connection) -> buf.write "\u0000\u0000\u0000\u0000", 4, 4, "binary" buf.writeInt16BE remotePort, 8 connection.write buf - # connect remote server - req = http.request( - host: aServer, - port: REMOTE_PORT, - headers: - 'Connection': 'Upgrade', - 'Upgrade': 'websocket' - ) - req.setNoDelay true - req.end() - req.setTimeout timeout, -> - req.abort() - connection.end() - req.on 'error', (e)-> - console.warn "req #{e}" - req.abort() - connection.end() - req.on 'upgrade', (res, conn, upgradeHead) -> - remote = conn - console.log "remote got upgrade" + # connect to remote server + ws = new WebSocket("ws://#{aServer}:#{REMOTE_PORT}/") + ws.on "open", -> console.log "connecting #{remoteAddr} via #{aServer}" addrToSendBuf = new Buffer(addrToSend, "binary") addrToSendBuf = encryptor.encrypt addrToSendBuf - remote.write addrToSendBuf + ws.send addrToSendBuf, { binary: true } i = 0 while i < cachedPieces.length piece = cachedPieces[i] piece = encryptor.encrypt piece - remote.write piece + ws.send piece, { binary: true } i++ cachedPieces = null # save memory stage = 5 - remote.on "data", (data) -> - data = encryptor.decrypt data - remote.pause() unless connection.write(data) - - remote.on "end", -> - console.log "remote disconnected" - connection.end() - server.getConnections (err, count) -> - console.log "concurrent connections:", count - return - - remote.on "error", (e)-> - console.log "remote #{remoteAddr}:#{remotePort} error: #{e}" - if stage is 4 - connection.destroy() - return - connection.end() - server.getConnections (err, count) -> - console.log "concurrent connections:", count - return - - remote.on "drain", -> - connection.resume() - - remote.setTimeout timeout, -> - connection.end() - remote.destroy() + ws.on "message", (data, flags) -> + data = encryptor.decrypt data + connection.write(data) + + ws.on "close", -> + console.log "remote disconnected" + connection.destroy() + + ws.on "error", (e) -> + console.log "remote #{remoteAddr}:#{remotePort} error: #{e}" + connection.destroy() + server.getConnections (err, count) -> + console.log "concurrent connections:", count + return if data.length > headerLength buf = new Buffer(data.length - headerLength) @@ -181,38 +151,31 @@ server = net.createServer((connection) -> buf = null stage = 4 catch e - # may encounter index out of range + # may encounter index out of range console.log e connection.destroy() - remote.destroy() if remote else cachedPieces.push data if stage is 4 # remote server not connected # cache received buffers # make sure no data is lost connection.on "end", -> - remote.destroy() if remote + console.log "local disconnected" + ws.close() if ws server.getConnections (err, count) -> console.log "concurrent connections:", count return connection.on "error", (e)-> console.log "local error: #{e}" - req.abort() if req - remote.destroy() if remote + ws.close() if ws server.getConnections (err, count) -> console.log "concurrent connections:", count return - connection.on "drain", -> - # calling resume() when remote not is connected will crash node.js - remote.resume() if remote and stage is 5 - connection.setTimeout timeout, -> - req.abort() if req - remote.destroy() if remote connection.destroy() -) + ws.close() if ws server.listen PORT, LOCAL_ADDRESS, -> address = server.address() diff --git a/src/merge_sort.coffee b/src/merge_sort.coffee index b6b20d90..c3bffe00 100644 --- a/src/merge_sort.coffee +++ b/src/merge_sort.coffee @@ -5,11 +5,11 @@ merge = (left, right, comparison) -> result.push left.shift() else result.push right.shift() - result.push left.shift() while left.length > 0 - result.push right.shift() while right.length > 0 + result.push left.shift() while left.length > 0 + result.push right.shift() while right.length > 0 result merge_sort = (array, comparison) -> - return array if array.length < 2 + return array if array.length < 2 middle = Math.ceil(array.length / 2) merge merge_sort(array.slice(0, middle), comparison), merge_sort(array.slice(middle), comparison), comparison exports.merge_sort = merge_sort diff --git a/src/server.coffee b/src/server.coffee index 31f59a84..7b81bca3 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -2,6 +2,8 @@ net = require("net") fs = require("fs") path = require("path") http = require("http") +WebSocket = require('ws') +WebSocketServer = WebSocket.Server parseArgs = require("minimist") Encryptor = require("./encrypt").Encryptor @@ -32,19 +34,11 @@ PORT = config.remote_port KEY = config.password METHOD = config.method -server = http.createServer (req, res) -> - res.writeHead 200, 'Content-Type':'text/plain' - res.end 'Good Day!' +wss = new WebSocketServer port: PORT -server.on 'upgrade', (req, connection, head) -> - connection.write 'HTTP/1.1 101 Web Socket Protocol Handshake\r\n' + - 'Upgrade: WebSocket\r\n' + - 'Connection: Upgrade\r\n' + - '\r\n' +wss.on "connection", (ws) -> console.log "server connected" - server.getConnections (err, count) -> - console.log "concurrent connections:", count - return + console.log "concurrent connections:", wss.clients.length encryptor = new Encryptor(KEY, METHOD) stage = 0 headerLength = 0 @@ -53,10 +47,10 @@ server.on 'upgrade', (req, connection, head) -> addrLen = 0 remoteAddr = null remotePort = null - connection.on "data", (data) -> + ws.on "message", (data, flags) -> data = encryptor.decrypt data if stage is 5 - connection.pause() unless remote.write(data) + remote.write(data) return if stage is 0 try @@ -65,7 +59,7 @@ server.on 'upgrade', (req, connection, head) -> addrLen = data[1] else unless addrtype is 1 console.warn "unsupported addrtype: " + addrtype - connection.end() + ws.close() return # read address and port if addrtype is 1 @@ -76,7 +70,7 @@ server.on 'upgrade', (req, connection, head) -> remoteAddr = data.slice(2, 2 + addrLen).toString("binary") remotePort = data.readUInt16BE(2 + addrLen) headerLength = 2 + addrLen + 2 - console.log remoteAddr + # connect remote server remote = net.connect(remotePort, remoteAddr, -> console.log "connecting", remoteAddr @@ -91,28 +85,19 @@ server.on 'upgrade', (req, connection, head) -> ) remote.on "data", (data) -> data = encryptor.encrypt data - remote.pause() unless connection.write(data) + ws.send data, { binary: true } if ws.readyState is WebSocket.OPEN remote.on "end", -> + ws.emit "close" console.log "remote disconnected" - server.getConnections (err, count) -> - console.log "concurrent connections:", count - return - connection.end() remote.on "error", (e)-> - console.log "remote : #{e}" - connection.destroy() - server.getConnections (err, count) -> - console.log "concurrent connections:", count - return - - remote.on "drain", -> - connection.resume() + ws.emit "close" + console.log "remote: #{e}" remote.setTimeout timeout, -> - connection.end() remote.destroy() + ws.close() if data.length > headerLength # make sure no data is lost @@ -124,38 +109,19 @@ server.on 'upgrade', (req, connection, head) -> catch e # may encouter index out of range console.warn e - connection.destroy() remote.destroy() if remote + ws.close() else cachedPieces.push data if stage is 4 # remote server not connected # cache received buffers # make sure no data is lost - connection.on "end", -> + ws.on "close", -> console.log "server disconnected" + console.log "concurrent connections:", wss.clients.length remote.destroy() if remote - server.getConnections (err, count) -> - console.log "concurrent connections:", count - return - connection.on "error", (e)-> + ws.on "error", (e) -> console.warn "server: #{e}" + console.log "concurrent connections:", wss.clients.length remote.destroy() if remote - server.getConnections (err, count) -> - console.log "concurrent connections:", count - return - - connection.on "drain", -> - remote.resume() if remote - - connection.setTimeout timeout, -> - remote.destroy() if remote - connection.destroy() - -server.listen PORT, -> - address = server.address() - console.log "server listening at", address - -server.on "error", (e) -> - console.warn "Address in use, aborting" if e.code is "EADDRINUSE" - process.exit 1 From b4d1140d2bc0ea94fd119d29358f1acdda079f20 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 6 Jan 2015 13:07:58 +0800 Subject: [PATCH 11/76] Ping every 50 seconds. --- config.json | 2 +- local.js | 10 ++++++++-- server.js | 4 ++++ src/local.coffee | 8 ++++++++ src/server.coffee | 4 ++++ 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/config.json b/config.json index 56373b86..8db54f6b 100644 --- a/config.json +++ b/config.json @@ -4,6 +4,6 @@ ], "local_port": 1080, "password": "`try*(^^$some^$%^complex>:<>?~password/", - "timeout": 50, + "timeout": 600, "method": "rc4" } diff --git a/local.js b/local.js index 004c3ff8..eaccaa2e 100644 --- a/local.js +++ b/local.js @@ -73,7 +73,7 @@ }; server = net.createServer(function(connection) { - var aServer, addrLen, addrToSend, cachedPieces, encryptor, headerLength, remoteAddr, remotePort, stage, ws; + var aServer, addrLen, addrToSend, cachedPieces, encryptor, headerLength, ping, remoteAddr, remotePort, stage, ws; console.log("local connected"); server.getConnections(function(err, count) { console.log("concurrent connections:", count); @@ -84,6 +84,7 @@ cachedPieces = []; addrLen = 0; ws = null; + ping = null; remoteAddr = null; remotePort = null; addrToSend = ""; @@ -157,13 +158,17 @@ i++; } cachedPieces = null; - return stage = 5; + stage = 5; + ping = setInterval(function() { + return ws.ping("", null, true); + }, 50); }); ws.on("message", function(data, flags) { data = encryptor.decrypt(data); return connection.write(data); }); ws.on("close", function() { + clearInterval(ping); console.log("remote disconnected"); return connection.destroy(); }); @@ -211,6 +216,7 @@ }); }); return connection.setTimeout(timeout, function() { + console.log("local timeout"); connection.destroy(); if (ws) { return ws.close(); diff --git a/server.js b/server.js index 35986c74..eae7acf2 100644 --- a/server.js +++ b/server.js @@ -130,6 +130,7 @@ return console.log("remote: " + e); }); remote.setTimeout(timeout, function() { + console.log("remote timeout"); remote.destroy(); return ws.close(); }); @@ -154,6 +155,9 @@ } } }); + ws.on("ping", function() { + return ws.pong('', null, true); + }); ws.on("close", function() { console.log("server disconnected"); console.log("concurrent connections:", wss.clients.length); diff --git a/src/local.coffee b/src/local.coffee index 39dc181a..a55c79ad 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -57,6 +57,7 @@ server = net.createServer (connection) -> cachedPieces = [] addrLen = 0 ws = null + ping = null remoteAddr = null remotePort = null addrToSend = "" @@ -129,11 +130,17 @@ server = net.createServer (connection) -> cachedPieces = null # save memory stage = 5 + ping = setInterval(-> + ws.ping "", null, true + , 50) + return + ws.on "message", (data, flags) -> data = encryptor.decrypt data connection.write(data) ws.on "close", -> + clearInterval ping console.log "remote disconnected" connection.destroy() @@ -174,6 +181,7 @@ server = net.createServer (connection) -> return connection.setTimeout timeout, -> + console.log "local timeout" connection.destroy() ws.close() if ws diff --git a/src/server.coffee b/src/server.coffee index 7b81bca3..22706d21 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -96,6 +96,7 @@ wss.on "connection", (ws) -> console.log "remote: #{e}" remote.setTimeout timeout, -> + console.log "remote timeout" remote.destroy() ws.close() @@ -116,6 +117,9 @@ wss.on "connection", (ws) -> # cache received buffers # make sure no data is lost + ws.on "ping", -> + ws.pong '', null, true + ws.on "close", -> console.log "server disconnected" console.log "concurrent connections:", wss.clients.length From c40ba52576c79bc77c7efde6caf24802c0400ef0 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 8 Jan 2015 00:43:52 +0800 Subject: [PATCH 12/76] It's in milliseconds, Jim --- local.js | 2 +- src/local.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/local.js b/local.js index eaccaa2e..4de7d9e1 100644 --- a/local.js +++ b/local.js @@ -161,7 +161,7 @@ stage = 5; ping = setInterval(function() { return ws.ping("", null, true); - }, 50); + }, 50 * 1000); }); ws.on("message", function(data, flags) { data = encryptor.decrypt(data); diff --git a/src/local.coffee b/src/local.coffee index a55c79ad..eea256f3 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -132,7 +132,7 @@ server = net.createServer (connection) -> ping = setInterval(-> ws.ping "", null, true - , 50) + , 50 * 1000) return ws.on "message", (data, flags) -> From 4cc9caaab79e9eba033f1ad65cc030dc2f0e842a Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Fri, 9 Jan 2015 02:04:30 +0800 Subject: [PATCH 13/76] Nodetime --- package.json | 1 + server.js | 6 ++++++ src/server.coffee | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/package.json b/package.json index fbb43c2d..7ee7ce6e 100644 --- a/package.json +++ b/package.json @@ -3,6 +3,7 @@ "version": "0.9.8", "dependencies": { "minimist": "^1.1.0", + "nodetime": "^0.8.15", "ws": "^0.6.3" }, "engines": { diff --git a/server.js b/server.js index eae7acf2..37d6e2e7 100644 --- a/server.js +++ b/server.js @@ -2,6 +2,12 @@ (function() { var Encryptor, KEY, METHOD, PORT, WebSocket, WebSocketServer, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, timeout, v, wss; + if (process.env.NODETIME_ACCOUNT_KEY) { + require("nodetime").profile({ + accountKey: process.env.NODETIME_ACCOUNT_KEY + }); + } + net = require("net"); fs = require("fs"); diff --git a/src/server.coffee b/src/server.coffee index 22706d21..e0ffdd91 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -1,3 +1,7 @@ +if process.env.NODETIME_ACCOUNT_KEY + require("nodetime").profile + accountKey: process.env.NODETIME_ACCOUNT_KEY + net = require("net") fs = require("fs") path = require("path") From 5aa721b38f650ff73d5e8684874ef61287580b7e Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Fri, 9 Jan 2015 15:01:10 +0800 Subject: [PATCH 14/76] fix test --- config.json | 5 ++--- local.js | 5 +---- server.js | 27 +++++++++++++++++++++++--- src/local.coffee | 5 +---- src/server.coffee | 17 +++++++++++++--- src/test.coffee | 4 ++-- test.js | 4 ++-- test_http.js | 49 ----------------------------------------------- 8 files changed, 46 insertions(+), 70 deletions(-) delete mode 100644 test_http.js diff --git a/config.json b/config.json index 8db54f6b..d548e058 100644 --- a/config.json +++ b/config.json @@ -1,8 +1,7 @@ { - "server": [ - "still-tor-8707.herokuapp.com" - ], + "server": "127.0.0.1", "local_port": 1080, + "remote_port": 8080, "password": "`try*(^^$some^$%^complex>:<>?~password/", "timeout": 600, "method": "rc4" diff --git a/local.js b/local.js index 4de7d9e1..cd9345f1 100644 --- a/local.js +++ b/local.js @@ -28,9 +28,6 @@ }, string: ['local_address', 'server', 'password', 'config_file', 'method'], "default": { - 'local_address': '127.0.0.1', - 'local_port': 1080, - 'remote_port': 80, 'config_file': path.resolve(__dirname, "config.json") } }; @@ -232,7 +229,7 @@ server.on("error", function(e) { if (e.code === "EADDRINUSE") { - console.log("Address in use, aborting"); + console.log("address in use, aborting"); } return process.exit(1); }); diff --git a/server.js b/server.js index 37d6e2e7..6f33dd08 100644 --- a/server.js +++ b/server.js @@ -33,9 +33,6 @@ }, string: ['password', 'method', 'config_file'], "default": { - 'remote_port': process.env.PORT || 8080, - 'password': process.env.KEY, - 'method': process.env.METHOD, 'config_file': path.resolve(__dirname, "config.json") } }; @@ -52,6 +49,18 @@ config = JSON.parse(configContent); + if (process.env.PORT) { + config['remote_port'] = +process.env.PORT; + } + + if (process.env.KEY) { + config['password'] = process.env.KEY; + } + + if (process.env.METHOD) { + config['method'] = process.env.METHOD; + } + for (k in configFromArgs) { v = configFromArgs[k]; config[k] = v; @@ -180,4 +189,16 @@ }); }); + wss.on("listening", function(address) { + address = wss._server.address(); + return console.log("server listening at", address); + }); + + wss.on("error", function(e) { + if (e.code === "EADDRINUSE") { + console.log("address in use, aborting"); + } + return process.exit(1); + }); + }).call(this); diff --git a/src/local.coffee b/src/local.coffee index eea256f3..72aebb37 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -18,9 +18,6 @@ options = string: ['local_address', 'server', 'password', 'config_file', 'method'] default: - 'local_address': '127.0.0.1' - 'local_port': 1080 - 'remote_port': 80 'config_file': path.resolve(__dirname, "config.json") inetNtoa = (buf) -> @@ -190,5 +187,5 @@ server.listen PORT, LOCAL_ADDRESS, -> console.log "server listening at", address server.on "error", (e) -> - console.log "Address in use, aborting" if e.code is "EADDRINUSE" + console.log "address in use, aborting" if e.code is "EADDRINUSE" process.exit 1 diff --git a/src/server.coffee b/src/server.coffee index e0ffdd91..14794173 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -19,9 +19,6 @@ options = 'm': 'method' string: ['password', 'method', 'config_file'] default: - 'remote_port': process.env.PORT || 8080 - 'password': process.env.KEY - 'method': process.env.METHOD 'config_file': path.resolve(__dirname, "config.json") inetNtoa = (buf) -> @@ -31,8 +28,14 @@ configFromArgs = parseArgs process.argv.slice(2), options configFile = configFromArgs.config_file configContent = fs.readFileSync(configFile) config = JSON.parse(configContent) + +config['remote_port'] = +process.env.PORT if process.env.PORT +config['password'] = process.env.KEY if process.env.KEY +config['method'] = process.env.METHOD if process.env.METHOD + for k, v of configFromArgs config[k] = v + timeout = Math.floor(config.timeout * 1000) PORT = config.remote_port KEY = config.password @@ -133,3 +136,11 @@ wss.on "connection", (ws) -> console.warn "server: #{e}" console.log "concurrent connections:", wss.clients.length remote.destroy() if remote + +wss.on "listening", (address) -> + address = wss._server.address() + console.log "server listening at", address + +wss.on "error", (e) -> + console.log "address in use, aborting" if e.code is "EADDRINUSE" + process.exit 1 diff --git a/src/test.coffee b/src/test.coffee index 55768982..e79432c7 100644 --- a/src/test.coffee +++ b/src/test.coffee @@ -62,14 +62,14 @@ server.stderr.on 'data', (data) -> local.stdout.on 'data', (data) -> console.log data.toString() - if data.toString().indexOf('listening at port') >= 0 + if data.toString().indexOf('listening at') >= 0 localReady = true if localReady and serverReady and not curlRunning runCurl() server.stdout.on 'data', (data) -> console.log data.toString() - if data.toString().indexOf('listening at port') >= 0 + if data.toString().indexOf('listening at') >= 0 serverReady = true if localReady and serverReady and not curlRunning runCurl() diff --git a/test.js b/test.js index 2ed579ec..4e8db470 100644 --- a/test.js +++ b/test.js @@ -79,7 +79,7 @@ local.stdout.on('data', function(data) { console.log(data.toString()); - if (data.toString().indexOf('listening at port') >= 0) { + if (data.toString().indexOf('listening at') >= 0) { localReady = true; if (localReady && serverReady && !curlRunning) { return runCurl(); @@ -89,7 +89,7 @@ server.stdout.on('data', function(data) { console.log(data.toString()); - if (data.toString().indexOf('listening at port') >= 0) { + if (data.toString().indexOf('listening at') >= 0) { serverReady = true; if (localReady && serverReady && !curlRunning) { return runCurl(); diff --git a/test_http.js b/test_http.js deleted file mode 100644 index 6e4c002c..00000000 --- a/test_http.js +++ /dev/null @@ -1,49 +0,0 @@ -var http = require('http'); - -// Create an HTTP server -var srv = http.createServer(function (req, res) { - res.writeHead(200, {'Content-Type':'text/plain'}); - console.log('okay'); - res.end('okay'); -}); -srv.on('upgrade', function (req, socket, head) { - socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' + - 'Upgrade: WebSocket\r\n' + - 'Connection: Upgrade\r\n' + - '\r\n'); - socket.on('data', function (data) { - console.log('srv on data'); - console.log(data); - socket.write('hello'); - }); - -// socket.pipe(socket); // echo back -}); - -// now that server is running -srv.listen(1337, '127.0.0.1', function () { - - // make a request - var options = { - port:1337, - host:'127.0.0.1', - headers:{ - 'Connection':'Upgrade', - 'Upgrade':'websocket' - } - }; - - var req = http.request(options); - req.end(); - - req.on('upgrade', function (res, socket, upgradeHead) { - console.log('got upgraded!'); - socket.write('test'); - socket.on('data', function (data) { - console.log('req on data'); - console.log(data); - }); -// socket.end(); -// process.exit(0); - }); -}); \ No newline at end of file From 68b91d4fb01fa725eab1b04baa6d023ae8c98cac Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Mon, 12 Jan 2015 00:26:20 +0800 Subject: [PATCH 15/76] pause/resume socket properly closes issue #2 --- README.md | 4 ++-- config.json | 1 + local.js | 27 ++++++++++++++++++++------- server.js | 21 +++++++++++++++++---- src/local.coffee | 19 ++++++++++++++----- src/server.coffee | 17 +++++++++++++---- 6 files changed, 67 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 3befa4dd..de0cae39 100644 --- a/README.md +++ b/README.md @@ -54,8 +54,8 @@ ws@0.6.4 node_modules/ws Then run: ``` -$ node local.js -s still-tor-8707.herokuapp.com -l 1080 -m rc4 -k foobar -shadowsocks-heroku v0.9.6 +$ node local.js -s still-tor-8707.herokuapp.com -l 1080 -m rc4 -k foobar -r 80 +server listening at { address: '0.0.0.0', family: 'IPv4', port: 1080 } ``` Change proxy settings of your browser into: diff --git a/config.json b/config.json index d548e058..ffef71be 100644 --- a/config.json +++ b/config.json @@ -1,5 +1,6 @@ { "server": "127.0.0.1", + "local_address": "127.0.0.1", "local_port": 1080, "remote_port": 8080, "password": "`try*(^^$some^$%^complex>:<>?~password/", diff --git a/local.js b/local.js index cd9345f1..b3e54c48 100644 --- a/local.js +++ b/local.js @@ -90,9 +90,14 @@ var addrtype, buf, cmd, e, reply, tempBuf; if (stage === 5) { data = encryptor.encrypt(data); - ws.send(data, { - binary: true - }); + if (ws.readyState === WebSocket.OPEN) { + ws.send(data, { + binary: true + }); + if (ws.bufferedAmount > 0) { + connection.pause(); + } + } return; } if (stage === 0) { @@ -159,10 +164,15 @@ ping = setInterval(function() { return ws.ping("", null, true); }, 50 * 1000); + ws._socket.on("drain", function() { + return connection.resume(); + }); }); ws.on("message", function(data, flags) { data = encryptor.decrypt(data); - return connection.write(data); + if (!connection.write(data)) { + return ws._socket.pause(); + } }); ws.on("close", function() { clearInterval(ping); @@ -197,7 +207,7 @@ connection.on("end", function() { console.log("local disconnected"); if (ws) { - ws.close(); + ws.terminate(); } return server.getConnections(function(err, count) { console.log("concurrent connections:", count); @@ -206,17 +216,20 @@ connection.on("error", function(e) { console.log("local error: " + e); if (ws) { - ws.close(); + ws.terminate(); } return server.getConnections(function(err, count) { console.log("concurrent connections:", count); }); }); + connection.on("drain", function() { + return ws._socket.resume(); + }); return connection.setTimeout(timeout, function() { console.log("local timeout"); connection.destroy(); if (ws) { - return ws.close(); + return ws.terminate(); } }); }); diff --git a/server.js b/server.js index 6f33dd08..86df2aca 100644 --- a/server.js +++ b/server.js @@ -94,7 +94,9 @@ var addrtype, buf, e; data = encryptor.decrypt(data); if (stage === 5) { - remote.write(data); + if (!remote.write(data)) { + ws._socket.pause(); + } return; } if (stage === 0) { @@ -131,17 +133,23 @@ remote.on("data", function(data) { data = encryptor.encrypt(data); if (ws.readyState === WebSocket.OPEN) { - return ws.send(data, { + ws.send(data, { binary: true }); + if (ws.bufferedAmount > 0) { + remote.pause(); + } } }); remote.on("end", function() { - ws.emit("close"); + ws.close(); return console.log("remote disconnected"); }); + remote.on("drain", function() { + return ws._socket.resume(); + }); remote.on("error", function(e) { - ws.emit("close"); + ws.terminate(); return console.log("remote: " + e); }); remote.setTimeout(timeout, function() { @@ -173,6 +181,11 @@ ws.on("ping", function() { return ws.pong('', null, true); }); + ws._socket.on("drain", function() { + if (stage === 5) { + return remote.resume(); + } + }); ws.on("close", function() { console.log("server disconnected"); console.log("concurrent connections:", wss.clients.length); diff --git a/src/local.coffee b/src/local.coffee index 72aebb37..eb692674 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -63,7 +63,9 @@ server = net.createServer (connection) -> if stage is 5 # pipe sockets data = encryptor.encrypt data - ws.send data, { binary: true } + if ws.readyState is WebSocket.OPEN + ws.send data, { binary: true } + connection.pause() if ws.bufferedAmount > 0 return if stage is 0 tempBuf = new Buffer(2) @@ -130,11 +132,15 @@ server = net.createServer (connection) -> ping = setInterval(-> ws.ping "", null, true , 50 * 1000) + + ws._socket.on "drain", -> + connection.resume() + return ws.on "message", (data, flags) -> data = encryptor.decrypt data - connection.write(data) + ws._socket.pause() unless connection.write(data) ws.on "close", -> clearInterval ping @@ -165,22 +171,25 @@ server = net.createServer (connection) -> connection.on "end", -> console.log "local disconnected" - ws.close() if ws + ws.terminate() if ws server.getConnections (err, count) -> console.log "concurrent connections:", count return connection.on "error", (e)-> console.log "local error: #{e}" - ws.close() if ws + ws.terminate() if ws server.getConnections (err, count) -> console.log "concurrent connections:", count return + connection.on "drain", -> + ws._socket.resume() + connection.setTimeout timeout, -> console.log "local timeout" connection.destroy() - ws.close() if ws + ws.terminate() if ws server.listen PORT, LOCAL_ADDRESS, -> address = server.address() diff --git a/src/server.coffee b/src/server.coffee index 14794173..ebda962f 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -57,7 +57,7 @@ wss.on "connection", (ws) -> ws.on "message", (data, flags) -> data = encryptor.decrypt data if stage is 5 - remote.write(data) + ws._socket.pause() unless remote.write(data) return if stage is 0 try @@ -92,14 +92,20 @@ wss.on "connection", (ws) -> ) remote.on "data", (data) -> data = encryptor.encrypt data - ws.send data, { binary: true } if ws.readyState is WebSocket.OPEN + if ws.readyState is WebSocket.OPEN + ws.send data, { binary: true } + remote.pause() if ws.bufferedAmount > 0 + return remote.on "end", -> - ws.emit "close" + ws.close() console.log "remote disconnected" + remote.on "drain", -> + ws._socket.resume() + remote.on "error", (e)-> - ws.emit "close" + ws.terminate() console.log "remote: #{e}" remote.setTimeout timeout, -> @@ -127,6 +133,9 @@ wss.on "connection", (ws) -> ws.on "ping", -> ws.pong '', null, true + ws._socket.on "drain", -> + remote.resume() if stage is 5 + ws.on "close", -> console.log "server disconnected" console.log "concurrent connections:", wss.clients.length From b113071469bac96b7c62c11bb0da382fe2e320ec Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Mon, 12 Jan 2015 12:54:27 +0800 Subject: [PATCH 16/76] Revert "Nodetime" This reverts commit 4cc9caaab79e9eba033f1ad65cc030dc2f0e842a. --- package.json | 1 - server.js | 6 ------ src/server.coffee | 4 ---- 3 files changed, 11 deletions(-) diff --git a/package.json b/package.json index 7ee7ce6e..fbb43c2d 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,6 @@ "version": "0.9.8", "dependencies": { "minimist": "^1.1.0", - "nodetime": "^0.8.15", "ws": "^0.6.3" }, "engines": { diff --git a/server.js b/server.js index 86df2aca..ff7c6a0d 100644 --- a/server.js +++ b/server.js @@ -2,12 +2,6 @@ (function() { var Encryptor, KEY, METHOD, PORT, WebSocket, WebSocketServer, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, timeout, v, wss; - if (process.env.NODETIME_ACCOUNT_KEY) { - require("nodetime").profile({ - accountKey: process.env.NODETIME_ACCOUNT_KEY - }); - } - net = require("net"); fs = require("fs"); diff --git a/src/server.coffee b/src/server.coffee index ebda962f..2882d0f5 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -1,7 +1,3 @@ -if process.env.NODETIME_ACCOUNT_KEY - require("nodetime").profile - accountKey: process.env.NODETIME_ACCOUNT_KEY - net = require("net") fs = require("fs") path = require("path") From 7fff934ac68e917f0ece2bdcbfd2e7b76ed23160 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Mon, 12 Jan 2015 16:49:12 +0800 Subject: [PATCH 17/76] Specify `table` cipher on command line. --- local.js | 6 +++++- server.js | 6 +++++- src/local.coffee | 3 +++ src/server.coffee | 3 +++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/local.js b/local.js index b3e54c48..cbbba223 100644 --- a/local.js +++ b/local.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SERVER, WebSocket, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, server, timeout, v; + var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SERVER, WebSocket, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, server, timeout, v, _ref; net = require("net"); @@ -61,6 +61,10 @@ timeout = Math.floor(config.timeout * 1000); + if ((_ref = METHOD.toLowerCase()) === "" || _ref === "null" || _ref === "table") { + METHOD = null; + } + getServer = function() { if (SERVER instanceof Array) { return SERVER[Math.floor(Math.random() * SERVER.length)]; diff --git a/server.js b/server.js index ff7c6a0d..2a68a4ab 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, KEY, METHOD, PORT, WebSocket, WebSocketServer, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, timeout, v, wss; + var Encryptor, KEY, METHOD, PORT, WebSocket, WebSocketServer, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, timeout, v, wss, _ref; net = require("net"); @@ -68,6 +68,10 @@ METHOD = config.method; + if ((_ref = METHOD.toLowerCase()) === "" || _ref === "null" || _ref === "table") { + METHOD = null; + } + wss = new WebSocketServer({ port: PORT }); diff --git a/src/local.coffee b/src/local.coffee index eb692674..2c45cd76 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -37,6 +37,9 @@ KEY = config.password METHOD = config.method timeout = Math.floor(config.timeout * 1000) +if METHOD.toLowerCase() in ["", "null", "table"] + METHOD = null + getServer = -> if SERVER instanceof Array SERVER[Math.floor(Math.random() * SERVER.length)] diff --git a/src/server.coffee b/src/server.coffee index 2882d0f5..cfc003a0 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -37,6 +37,9 @@ PORT = config.remote_port KEY = config.password METHOD = config.method +if METHOD.toLowerCase() in ["", "null", "table"] + METHOD = null + wss = new WebSocketServer port: PORT wss.on "connection", (ws) -> From 2b12fa1947dcfda67ccdfc4dde2d2df64e287efe Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 13 Jan 2015 01:11:56 +0800 Subject: [PATCH 18/76] Try node 0.11.x --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fbb43c2d..d9d8bc70 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,6 @@ "ws": "^0.6.3" }, "engines": { - "node": "0.10.x" + "node": "0.11.x" } } From 1fa9edf6fa6228074c1264971f3340e6d8f0e3a5 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 13 Jan 2015 10:15:30 +0800 Subject: [PATCH 19/76] Save a few Buffer allocation. --- encrypt.js | 8 ++------ src/encrypt.coffee | 6 ++---- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/encrypt.js b/encrypt.js index ee58ab75..b8c6eb38 100644 --- a/encrypt.js +++ b/encrypt.js @@ -68,20 +68,16 @@ } Encryptor.prototype.encrypt = function(buf) { - var result; if (this.method != null) { - result = new Buffer(this.cipher.update(buf.toString('binary')), 'binary'); - return result; + return this.cipher.update(buf); } else { return encrypt(this.encryptTable, buf); } }; Encryptor.prototype.decrypt = function(buf) { - var result; if (this.method != null) { - result = new Buffer(this.decipher.update(buf.toString('binary')), 'binary'); - return result; + return this.decipher.update(buf); } else { return encrypt(this.decryptTable, buf); } diff --git a/src/encrypt.coffee b/src/encrypt.coffee index 7bee6c9c..d1e74fc0 100644 --- a/src/encrypt.coffee +++ b/src/encrypt.coffee @@ -53,15 +53,13 @@ class Encryptor encrypt: (buf) -> if @method? - result = new Buffer(@cipher.update(buf.toString('binary')), 'binary') - result + @cipher.update(buf) else encrypt @encryptTable, buf decrypt: (buf) -> if @method? - result = new Buffer(@decipher.update(buf.toString('binary')), 'binary') - result + @decipher.update(buf) else encrypt @decryptTable, buf From b626e60298aaaec01b90ff5bb256998b78c812fd Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 13 Jan 2015 10:22:18 +0800 Subject: [PATCH 20/76] gc every second. --- Procfile | 2 +- local.js | 6 ++++++ server.js | 6 ++++++ src/local.coffee | 5 +++++ src/server.coffee | 5 +++++ 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Procfile b/Procfile index 489b2700..f3763e51 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node server.js +web: node --expose-gc server.js diff --git a/local.js b/local.js index cbbba223..f2e30ad1 100644 --- a/local.js +++ b/local.js @@ -73,6 +73,12 @@ } }; + setInterval(function() { + if (global.gc) { + return gc(); + } + }, 1000); + server = net.createServer(function(connection) { var aServer, addrLen, addrToSend, cachedPieces, encryptor, headerLength, ping, remoteAddr, remotePort, stage, ws; console.log("local connected"); diff --git a/server.js b/server.js index 2a68a4ab..2c8cf034 100644 --- a/server.js +++ b/server.js @@ -72,6 +72,12 @@ METHOD = null; } + setInterval(function() { + if (global.gc) { + return gc(); + } + }, 1000); + wss = new WebSocketServer({ port: PORT }); diff --git a/src/local.coffee b/src/local.coffee index 2c45cd76..05a59fd9 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -46,6 +46,11 @@ getServer = -> else SERVER +setInterval(-> + if global.gc + gc() +, 1000) + server = net.createServer (connection) -> console.log "local connected" server.getConnections (err, count) -> diff --git a/src/server.coffee b/src/server.coffee index cfc003a0..e6e4ff26 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -40,6 +40,11 @@ METHOD = config.method if METHOD.toLowerCase() in ["", "null", "table"] METHOD = null +setInterval(-> + if global.gc + gc() +, 1000) + wss = new WebSocketServer port: PORT wss.on "connection", (ws) -> From 3afb708179424eaf40367dd89516e3c228653b9d Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 13 Jan 2015 23:39:40 +0800 Subject: [PATCH 21/76] Bind server to specified interface. --- Procfile | 2 +- server.js | 23 +++++++++++++++++------ src/server.coffee | 16 +++++++++++----- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Procfile b/Procfile index f3763e51..2f83fb16 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node --expose-gc server.js +web: node --expose-gc server.js -b 0.0.0.0 diff --git a/server.js b/server.js index 2c8cf034..f03f9421 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, KEY, METHOD, PORT, WebSocket, WebSocketServer, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, timeout, v, wss, _ref; + var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, WebSocket, WebSocketServer, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, server, timeout, v, wss, _ref; net = require("net"); @@ -20,12 +20,13 @@ options = { alias: { + 'b': 'local_address', 'r': 'remote_port', 'k': 'password', 'c': 'config_file', 'm': 'method' }, - string: ['password', 'method', 'config_file'], + string: ['local_address', 'password', 'method', 'config_file'], "default": { 'config_file': path.resolve(__dirname, "config.json") } @@ -62,6 +63,8 @@ timeout = Math.floor(config.timeout * 1000); + LOCAL_ADDRESS = config.local_address; + PORT = config.remote_port; KEY = config.password; @@ -78,8 +81,15 @@ } }, 1000); + server = http.createServer(function(req, res) { + res.writeHead(200, { + 'Content-Type': 'text/plain' + }); + return res.end("asdf."); + }); + wss = new WebSocketServer({ - port: PORT + server: server }); wss.on("connection", function(ws) { @@ -206,12 +216,13 @@ }); }); - wss.on("listening", function(address) { - address = wss._server.address(); + server.listen(PORT, LOCAL_ADDRESS, function() { + var address; + address = server.address(); return console.log("server listening at", address); }); - wss.on("error", function(e) { + server.on("error", function(e) { if (e.code === "EADDRINUSE") { console.log("address in use, aborting"); } diff --git a/src/server.coffee b/src/server.coffee index e6e4ff26..59d52a1b 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -9,11 +9,12 @@ Encryptor = require("./encrypt").Encryptor options = alias: + 'b': 'local_address' 'r': 'remote_port' 'k': 'password', 'c': 'config_file', 'm': 'method' - string: ['password', 'method', 'config_file'] + string: ['local_address', 'password', 'method', 'config_file'] default: 'config_file': path.resolve(__dirname, "config.json") @@ -33,6 +34,7 @@ for k, v of configFromArgs config[k] = v timeout = Math.floor(config.timeout * 1000) +LOCAL_ADDRESS = config.local_address PORT = config.remote_port KEY = config.password METHOD = config.method @@ -45,7 +47,11 @@ setInterval(-> gc() , 1000) -wss = new WebSocketServer port: PORT +server = http.createServer (req, res) -> + res.writeHead 200, 'Content-Type': 'text/plain' + res.end("asdf.") + +wss = new WebSocketServer server: server wss.on "connection", (ws) -> console.log "server connected" @@ -150,10 +156,10 @@ wss.on "connection", (ws) -> console.log "concurrent connections:", wss.clients.length remote.destroy() if remote -wss.on "listening", (address) -> - address = wss._server.address() +server.listen PORT, LOCAL_ADDRESS, -> + address = server.address() console.log "server listening at", address -wss.on "error", (e) -> +server.on "error", (e) -> console.log "address in use, aborting" if e.code is "EADDRINUSE" process.exit 1 From 94c38226a146054d90ba9bf589d4f4eef2c07513 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Wed, 14 Jan 2015 01:26:39 +0800 Subject: [PATCH 22/76] Support specified WebSocket URL as server. --- config.json | 1 + local.js | 41 ++++++++++++++++++++++++++++++++++++++--- src/local.coffee | 21 +++++++++++++++++++-- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/config.json b/config.json index ffef71be..26c9f8c6 100644 --- a/config.json +++ b/config.json @@ -1,6 +1,7 @@ { "server": "127.0.0.1", "local_address": "127.0.0.1", + "scheme": "ws", "local_port": 1080, "remote_port": 8080, "password": "`try*(^^$some^$%^complex>:<>?~password/", diff --git a/local.js b/local.js index f2e30ad1..982f13b7 100644 --- a/local.js +++ b/local.js @@ -1,9 +1,11 @@ // Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SERVER, WebSocket, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, server, timeout, v, _ref; + var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SCHEME, SERVER, WebSocket, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, prepareServer, s, server, timeout, url, v, _ref; net = require("net"); + url = require("url"); + http = require("http"); fs = require("fs"); @@ -26,7 +28,7 @@ 'c': 'config_file', 'm': 'method' }, - string: ['local_address', 'server', 'password', 'config_file', 'method'], + string: ['local_address', 'server', 'password', 'config_file', 'method', 'scheme'], "default": { 'config_file': path.resolve(__dirname, "config.json") } @@ -47,6 +49,8 @@ config[k] = v; } + SCHEME = config.scheme; + SERVER = config.server; REMOTE_PORT = config.remote_port; @@ -65,6 +69,37 @@ METHOD = null; } + prepareServer = function(address) { + var serverUrl; + serverUrl = url.parse(address); + serverUrl.slashes = true; + if (serverUrl.protocol == null) { + serverUrl.protocol = SCHEME; + } + if (serverUrl.hostname === null) { + serverUrl.hostname = address; + serverUrl.pathname = '/'; + } + if (serverUrl.port == null) { + serverUrl.port = REMOTE_PORT; + } + return url.format(serverUrl); + }; + + if (SERVER instanceof Array) { + SERVER = (function() { + var _i, _len, _results; + _results = []; + for (_i = 0, _len = SERVER.length; _i < _len; _i++) { + s = SERVER[_i]; + _results.push(prepareServer(s)); + } + return _results; + })(); + } else { + SERVER = prepareServer(SERVER); + } + getServer = function() { if (SERVER instanceof Array) { return SERVER[Math.floor(Math.random() * SERVER.length)]; @@ -151,7 +186,7 @@ buf.write("\u0000\u0000\u0000\u0000", 4, 4, "binary"); buf.writeInt16BE(remotePort, 8); connection.write(buf); - ws = new WebSocket("ws://" + aServer + ":" + REMOTE_PORT + "/"); + ws = new WebSocket(aServer); ws.on("open", function() { var addrToSendBuf, i, piece; console.log("connecting " + remoteAddr + " via " + aServer); diff --git a/src/local.coffee b/src/local.coffee index 05a59fd9..a33aec51 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -1,4 +1,5 @@ net = require("net") +url = require("url") http = require("http") fs = require("fs") path = require("path") @@ -16,7 +17,7 @@ options = 'c': 'config_file', 'm': 'method' string: ['local_address', 'server', 'password', - 'config_file', 'method'] + 'config_file', 'method', 'scheme'] default: 'config_file': path.resolve(__dirname, "config.json") @@ -29,6 +30,7 @@ config = JSON.parse(configContent) for k, v of configFromArgs config[k] = v +SCHEME = config.scheme SERVER = config.server REMOTE_PORT = config.remote_port LOCAL_ADDRESS = config.local_address @@ -40,6 +42,21 @@ timeout = Math.floor(config.timeout * 1000) if METHOD.toLowerCase() in ["", "null", "table"] METHOD = null +prepareServer = (address) -> + serverUrl = url.parse address + serverUrl.slashes = true + serverUrl.protocol ?= SCHEME + if serverUrl.hostname is null + serverUrl.hostname = address + serverUrl.pathname = '/' + serverUrl.port ?= REMOTE_PORT + url.format(serverUrl) + +if SERVER instanceof Array + SERVER = (prepareServer(s) for s in SERVER) +else + SERVER = prepareServer(SERVER) + getServer = -> if SERVER instanceof Array SERVER[Math.floor(Math.random() * SERVER.length)] @@ -121,7 +138,7 @@ server = net.createServer (connection) -> buf.writeInt16BE remotePort, 8 connection.write buf # connect to remote server - ws = new WebSocket("ws://#{aServer}:#{REMOTE_PORT}/") + ws = new WebSocket(aServer) ws.on "open", -> console.log "connecting #{remoteAddr} via #{aServer}" addrToSendBuf = new Buffer(addrToSend, "binary") From e81f9650ff5994b49628bd85d7588852aa7d21c3 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 13 Jan 2015 13:36:47 +0800 Subject: [PATCH 23/76] OpenShift --- .openshift/README.md | 3 +++ .openshift/action_hooks/README.md | 3 +++ .openshift/cron/README.cron | 27 +++++++++++++++++++++++++++ .openshift/cron/daily/.gitignore | 0 .openshift/cron/hourly/.gitignore | 0 .openshift/cron/minutely/.gitignore | 0 .openshift/cron/monthly/.gitignore | 0 .openshift/cron/weekly/README | 16 ++++++++++++++++ .openshift/cron/weekly/chrono.dat | 1 + .openshift/cron/weekly/chronograph | 3 +++ .openshift/cron/weekly/jobs.allow | 12 ++++++++++++ .openshift/cron/weekly/jobs.deny | 7 +++++++ .openshift/markers/README.md | 3 +++ node_modules/.gitkeep | 0 package.json | 7 +++++-- server.js | 8 ++++++++ src/server.coffee | 4 ++++ 17 files changed, 92 insertions(+), 2 deletions(-) create mode 100644 .openshift/README.md create mode 100644 .openshift/action_hooks/README.md create mode 100644 .openshift/cron/README.cron create mode 100644 .openshift/cron/daily/.gitignore create mode 100644 .openshift/cron/hourly/.gitignore create mode 100644 .openshift/cron/minutely/.gitignore create mode 100644 .openshift/cron/monthly/.gitignore create mode 100644 .openshift/cron/weekly/README create mode 100644 .openshift/cron/weekly/chrono.dat create mode 100755 .openshift/cron/weekly/chronograph create mode 100644 .openshift/cron/weekly/jobs.allow create mode 100644 .openshift/cron/weekly/jobs.deny create mode 100644 .openshift/markers/README.md create mode 100644 node_modules/.gitkeep diff --git a/.openshift/README.md b/.openshift/README.md new file mode 100644 index 00000000..7ec66d79 --- /dev/null +++ b/.openshift/README.md @@ -0,0 +1,3 @@ +For information about .openshift directory, consult the documentation: + +http://openshift.github.io/documentation/oo_user_guide.html#the-openshift-directory diff --git a/.openshift/action_hooks/README.md b/.openshift/action_hooks/README.md new file mode 100644 index 00000000..54131958 --- /dev/null +++ b/.openshift/action_hooks/README.md @@ -0,0 +1,3 @@ +For information about action hooks, consult the documentation: + +http://openshift.github.io/documentation/oo_user_guide.html#action-hooks diff --git a/.openshift/cron/README.cron b/.openshift/cron/README.cron new file mode 100644 index 00000000..ac77f787 --- /dev/null +++ b/.openshift/cron/README.cron @@ -0,0 +1,27 @@ +Run scripts or jobs on a periodic basis +======================================= +Any scripts or jobs added to the minutely, hourly, daily, weekly or monthly +directories will be run on a scheduled basis (frequency is as indicated by the +name of the directory) using run-parts. + +run-parts ignores any files that are hidden or dotfiles (.*) or backup +files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} + +The presence of two specially named files jobs.deny and jobs.allow controls +how run-parts executes your scripts/jobs. + jobs.deny ===> Prevents specific scripts or jobs from being executed. + jobs.allow ===> Only execute the named scripts or jobs (all other/non-named + scripts that exist in this directory are ignored). + +The principles of jobs.deny and jobs.allow are the same as those of cron.deny +and cron.allow and are described in detail at: + http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/ch-Automating_System_Tasks.html#s2-autotasks-cron-access + +See: man crontab or above link for more details and see the the weekly/ + directory for an example. + +PLEASE NOTE: The Cron cartridge must be installed in order to run the configured jobs. + +For more information about cron, consult the documentation: +http://openshift.github.io/documentation/oo_cartridge_guide.html#cron +http://openshift.github.io/documentation/oo_user_guide.html#cron diff --git a/.openshift/cron/daily/.gitignore b/.openshift/cron/daily/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/.openshift/cron/hourly/.gitignore b/.openshift/cron/hourly/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/.openshift/cron/minutely/.gitignore b/.openshift/cron/minutely/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/.openshift/cron/monthly/.gitignore b/.openshift/cron/monthly/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/.openshift/cron/weekly/README b/.openshift/cron/weekly/README new file mode 100644 index 00000000..7c3e659f --- /dev/null +++ b/.openshift/cron/weekly/README @@ -0,0 +1,16 @@ +Run scripts or jobs on a weekly basis +===================================== +Any scripts or jobs added to this directory will be run on a scheduled basis +(weekly) using run-parts. + +run-parts ignores any files that are hidden or dotfiles (.*) or backup +files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} and handles +the files named jobs.deny and jobs.allow specially. + +In this specific example, the chronograph script is the only script or job file +executed on a weekly basis (due to white-listing it in jobs.allow). And the +README and chrono.dat file are ignored either as a result of being black-listed +in jobs.deny or because they are NOT white-listed in the jobs.allow file. + +For more details, please see ../README.cron file. + diff --git a/.openshift/cron/weekly/chrono.dat b/.openshift/cron/weekly/chrono.dat new file mode 100644 index 00000000..fc4abb87 --- /dev/null +++ b/.openshift/cron/weekly/chrono.dat @@ -0,0 +1 @@ +Time And Relative D...n In Execution (Open)Shift! diff --git a/.openshift/cron/weekly/chronograph b/.openshift/cron/weekly/chronograph new file mode 100755 index 00000000..61de949f --- /dev/null +++ b/.openshift/cron/weekly/chronograph @@ -0,0 +1,3 @@ +#!/bin/bash + +echo "`date`: `cat $(dirname \"$0\")/chrono.dat`" diff --git a/.openshift/cron/weekly/jobs.allow b/.openshift/cron/weekly/jobs.allow new file mode 100644 index 00000000..8d32abc7 --- /dev/null +++ b/.openshift/cron/weekly/jobs.allow @@ -0,0 +1,12 @@ +# +# Script or job files listed in here (one entry per line) will be +# executed on a weekly-basis. +# +# Example: The chronograph script will be executed weekly but the README +# and chrono.dat files in this directory will be ignored. +# +# The README file is actually ignored due to the entry in the +# jobs.deny which is checked before jobs.allow (this file). +# +chronograph + diff --git a/.openshift/cron/weekly/jobs.deny b/.openshift/cron/weekly/jobs.deny new file mode 100644 index 00000000..73c94500 --- /dev/null +++ b/.openshift/cron/weekly/jobs.deny @@ -0,0 +1,7 @@ +# +# Any script or job files listed in here (one entry per line) will NOT be +# executed (read as ignored by run-parts). +# + +README + diff --git a/.openshift/markers/README.md b/.openshift/markers/README.md new file mode 100644 index 00000000..45814da3 --- /dev/null +++ b/.openshift/markers/README.md @@ -0,0 +1,3 @@ +For information about markers, consult the documentation: + +http://openshift.github.io/documentation/oo_user_guide.html#markers diff --git a/node_modules/.gitkeep b/node_modules/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/package.json b/package.json index d9d8bc70..a30d8fe5 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,9 @@ "ws": "^0.6.3" }, "engines": { - "node": "0.11.x" - } + "node": "0.10.x", + "npm": ">= 1.0.0" + }, + "private": true, + "main": "--expose-gc server.js" } diff --git a/server.js b/server.js index f03f9421..02e01a3b 100644 --- a/server.js +++ b/server.js @@ -44,6 +44,14 @@ config = JSON.parse(configContent); + if (process.env.OPENSHIFT_NODEJS_IP) { + config['local_address'] = process.env.OPENSHIFT_NODEJS_IP; + } + + if (process.env.OPENSHIFT_NODEJS_PORT) { + config['remote_port'] = +process.env.OPENSHIFT_NODEJS_PORT; + } + if (process.env.PORT) { config['remote_port'] = +process.env.PORT; } diff --git a/src/server.coffee b/src/server.coffee index 59d52a1b..e2e78734 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -26,6 +26,10 @@ configFile = configFromArgs.config_file configContent = fs.readFileSync(configFile) config = JSON.parse(configContent) +# OpenShift +config['local_address'] = process.env.OPENSHIFT_NODEJS_IP if process.env.OPENSHIFT_NODEJS_IP +config['remote_port'] = +process.env.OPENSHIFT_NODEJS_PORT if process.env.OPENSHIFT_NODEJS_PORT +# Heroku config['remote_port'] = +process.env.PORT if process.env.PORT config['password'] = process.env.KEY if process.env.KEY config['method'] = process.env.METHOD if process.env.METHOD From a3e10611a2c56622540f72c120884ebe9a2ee3f9 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Wed, 14 Jan 2015 11:05:43 +0800 Subject: [PATCH 24/76] Support `null` cipher. --- encrypt.js | 24 +++++++++++++++--------- local.js | 2 +- server.js | 2 +- src/encrypt.coffee | 24 +++++++++++++++--------- src/local.coffee | 2 +- src/server.coffee | 2 +- 6 files changed, 34 insertions(+), 22 deletions(-) diff --git a/encrypt.js b/encrypt.js index b8c6eb38..0d3a81ad 100644 --- a/encrypt.js +++ b/encrypt.js @@ -59,27 +59,33 @@ function Encryptor(key, method) { var _ref; this.method = method; - if (this.method != null) { + if (this.method === null) { + return; + } else if (this.method === "table") { + _ref = getTable(key), this.encryptTable = _ref[0], this.decryptTable = _ref[1]; + } else { this.cipher = crypto.createCipher(this.method, key); this.decipher = crypto.createDecipher(this.method, key); - } else { - _ref = getTable(key), this.encryptTable = _ref[0], this.decryptTable = _ref[1]; } } Encryptor.prototype.encrypt = function(buf) { - if (this.method != null) { - return this.cipher.update(buf); - } else { + if (this.method === null) { + return buf; + } else if (this.method === "table") { return encrypt(this.encryptTable, buf); + } else { + return this.cipher.update(buf); } }; Encryptor.prototype.decrypt = function(buf) { - if (this.method != null) { - return this.decipher.update(buf); - } else { + if (this.method === null) { + return buf; + } else if (this.method === "table") { return encrypt(this.decryptTable, buf); + } else { + return this.decipher.update(buf); } }; diff --git a/local.js b/local.js index 982f13b7..79199abf 100644 --- a/local.js +++ b/local.js @@ -65,7 +65,7 @@ timeout = Math.floor(config.timeout * 1000); - if ((_ref = METHOD.toLowerCase()) === "" || _ref === "null" || _ref === "table") { + if ((METHOD != null) && ((_ref = METHOD.toLowerCase()) === "" || _ref === "null")) { METHOD = null; } diff --git a/server.js b/server.js index 02e01a3b..991cd0bb 100644 --- a/server.js +++ b/server.js @@ -79,7 +79,7 @@ METHOD = config.method; - if ((_ref = METHOD.toLowerCase()) === "" || _ref === "null" || _ref === "table") { + if ((METHOD != null) && ((_ref = METHOD.toLowerCase()) === "" || _ref === "null")) { METHOD = null; } diff --git a/src/encrypt.coffee b/src/encrypt.coffee index d1e74fc0..14650eea 100644 --- a/src/encrypt.coffee +++ b/src/encrypt.coffee @@ -45,23 +45,29 @@ encrypt = (table, buf) -> class Encryptor constructor: (key, @method) -> - if @method? + if @method is null + return + else if @method == "table" + [@encryptTable, @decryptTable] = getTable(key) + else @cipher = crypto.createCipher @method, key @decipher = crypto.createDecipher @method, key - else - [@encryptTable, @decryptTable] = getTable(key) encrypt: (buf) -> - if @method? - @cipher.update(buf) - else + if @method is null + buf + else if @method == "table" encrypt @encryptTable, buf + else + @cipher.update(buf) decrypt: (buf) -> - if @method? - @decipher.update(buf) - else + if @method is null + buf + else if @method == "table" encrypt @decryptTable, buf + else + @decipher.update(buf) exports.Encryptor = Encryptor exports.getTable = getTable diff --git a/src/local.coffee b/src/local.coffee index a33aec51..8ae4a331 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -39,7 +39,7 @@ KEY = config.password METHOD = config.method timeout = Math.floor(config.timeout * 1000) -if METHOD.toLowerCase() in ["", "null", "table"] +if METHOD? and (METHOD.toLowerCase() in ["", "null"]) METHOD = null prepareServer = (address) -> diff --git a/src/server.coffee b/src/server.coffee index e2e78734..7eb9450e 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -43,7 +43,7 @@ PORT = config.remote_port KEY = config.password METHOD = config.method -if METHOD.toLowerCase() in ["", "null", "table"] +if METHOD? and (METHOD.toLowerCase() in ["", "null"]) METHOD = null setInterval(-> From 4a7719730c3e4802f24acd28e96f49d50a09fb2f Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Wed, 14 Jan 2015 11:56:17 +0800 Subject: [PATCH 25/76] Document OpenShift support. --- README.md | 109 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index de0cae39..5bdb8cb9 100644 --- a/README.md +++ b/README.md @@ -3,16 +3,18 @@ shadowsocks-heroku shadowsocks-heroku is a lightweight tunnel proxy which can help you get through firewalls. It is a port of [shadowsocks](https://github.com/clowwindy/shadowsocks), but through a different protocol. -shadowsocks-heroku uses WebSocket instead of raw sockets, so it can be deployed on [Heroku](https://www.heroku.com/). +shadowsocks-heroku uses WebSocket instead of raw sockets, so it can be deployed on [Heroku](https://www.heroku.com/) and [OpenShift](https://www.openshift.com/). Notice that the protocol is INCOMPATIBLE with the origin shadowsocks. -Usage ------ +Heroku +------ + +### Usage ``` $ heroku create -Creating still-tor-8707... done, stack is cedar +Creating still-tor-8707... done, stack is cedar-14 http://still-tor-8707.herokuapp.com/ | git@heroku.com:still-tor-8707.git ``` @@ -64,11 +66,106 @@ Change proxy settings of your browser into: SOCKS5 127.0.0.1:1080 ``` -Troubleshooting ---------------- +### Troubleshooting If there is something wrong, you can check the logs by: ``` $ heroku logs -t --app still-tor-8707 ``` + +OpenShift +--------- + +### Usage + +``` +$ rhc app create asdfasdf nodejs-0.10 +Application Options +------------------- +Domain: qwert +Cartridges: nodejs-0.10 +Gear Size: default +Scaling: no + +Creating application 'asdfasdf' ... done +… + +Your application 'asdfasdf' is now available. + + URL: http://asdfasdf-qwert.rhcloud.com/ + SSH to: 54b5e30d4382ec020700010d@asdfasdf-qwert.rhcloud.com + Git remote: ssh://54b5e30d4382ec020700010d@asdfasdf-qwert.rhcloud.com/~/git/asdfasdf.git/ + Cloned to: …/shadowsocks-heroku/asdfasdf + +Run 'rhc show-app asdfasdf' for more details about your app. +``` + +Push the code to OpenShift. + +``` +$ git remote add openshift ssh://54b5e30d4382ec020700010d@asdfasdf-qwert.rhcloud.com/~/git/asdfasdf.git +$ git push openshift -f +… +remote: npm info ok +remote: Preparing build for deployment +remote: Deployment id is 5b7aa220 +remote: Activating deployment +remote: Starting NodeJS cartridge +remote: Tue Jan 13 2015 22:42:36 GMT-0500 (EST): Starting application 'asdfasdf' ... +remote: ------------------------- +remote: Git Post-Receive Result: success +remote: Activation status: success +remote: Deployment completed with status: success +To ssh://54b5e30d4382ec020700010d@asdfasdf-qwert.rhcloud.com/~/git/asdfasdf.git + + 641794d...a3e1061 master -> master (forced update) +``` + +Set a few configs: + +``` +$ rhc env set METHOD=rc4 KEY=foobar -a asdfasdf +Setting environment variable(s) ... done +``` + +Restart application: + +``` +$ rhc app restart -a asdfasdf +RESULT: +asdfasdf restarted +``` + +Install project dependencies with `npm install`: + +``` +$ npm install +… +minimist@1.1.0 node_modules/minimist + +ws@0.6.4 node_modules/ws +├── options@0.0.6 +├── ultron@1.0.1 +└── nan@1.4.1 +``` + +Then run: + +``` +$ node local.js -m rc4 -k foobar -s 'wss://asdfasdf-qwert.rhcloud.com:8443' +server listening at { address: '127.0.0.1', family: 'IPv4', port: 1080 } +``` + +Change proxy settings of your browser into: + +``` +SOCKS5 127.0.0.1:1080 +``` + +### Troubleshooting + +If there is something wrong, you can check the logs by: + +``` +$ rhc tail -a asdfasdf +``` From d0a3ab2e9a3507e41be1cdf8a82bd209dee3d66d Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Wed, 14 Jan 2015 17:54:48 +0800 Subject: [PATCH 26/76] cleanup --- .travis.yml | 11 ----------- node_modules/.gitkeep | 0 package.json | 5 ++--- 3 files changed, 2 insertions(+), 14 deletions(-) delete mode 100644 .travis.yml delete mode 100644 node_modules/.gitkeep diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index d7390186..00000000 --- a/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -language: node_js -node_js: - - "0.10" - - "0.8" - - "0.6" -before_install: - - npm install -g coffee-script - - cp test/config.json . -script: - - cake build - - cake test diff --git a/node_modules/.gitkeep b/node_modules/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/package.json b/package.json index a30d8fe5..ca39d011 100644 --- a/package.json +++ b/package.json @@ -1,14 +1,13 @@ { "name": "shadowsocks-heroku", - "version": "0.9.8", + "version": "0.9.9", "dependencies": { "minimist": "^1.1.0", - "ws": "^0.6.3" + "ws": "^0.6.5" }, "engines": { "node": "0.10.x", "npm": ">= 1.0.0" }, - "private": true, "main": "--expose-gc server.js" } From c9492fb8ec67647c7bbd7bf3dc5512ac28481b52 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 15 Jan 2015 09:53:10 +0800 Subject: [PATCH 27/76] minor --- local.js | 8 ++++++-- src/local.coffee | 4 ++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/local.js b/local.js index 79199abf..826dc0d1 100644 --- a/local.js +++ b/local.js @@ -186,7 +186,9 @@ buf.write("\u0000\u0000\u0000\u0000", 4, 4, "binary"); buf.writeInt16BE(remotePort, 8); connection.write(buf); - ws = new WebSocket(aServer); + ws = new WebSocket(aServer, { + protocol: "binary, base64" + }); ws.on("open", function() { var addrToSendBuf, i, piece; console.log("connecting " + remoteAddr + " via " + aServer); @@ -268,7 +270,9 @@ }); }); connection.on("drain", function() { - return ws._socket.resume(); + if (ws && ws._socket) { + return ws._socket.resume(); + } }); return connection.setTimeout(timeout, function() { console.log("local timeout"); diff --git a/src/local.coffee b/src/local.coffee index 8ae4a331..5adcdb2a 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -138,7 +138,7 @@ server = net.createServer (connection) -> buf.writeInt16BE remotePort, 8 connection.write buf # connect to remote server - ws = new WebSocket(aServer) + ws = new WebSocket aServer, protocol: "binary, base64" ws.on "open", -> console.log "connecting #{remoteAddr} via #{aServer}" addrToSendBuf = new Buffer(addrToSend, "binary") @@ -209,7 +209,7 @@ server = net.createServer (connection) -> return connection.on "drain", -> - ws._socket.resume() + ws._socket.resume() if ws and ws._socket connection.setTimeout timeout, -> console.log "local timeout" From 1bacabfa19806f0f3b7803b0fc41fc78b7cec3dc Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Wed, 21 Jan 2015 18:58:57 +0800 Subject: [PATCH 28/76] Document supported ciphers. #7 --- README.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/README.md b/README.md index 5bdb8cb9..eb034cca 100644 --- a/README.md +++ b/README.md @@ -169,3 +169,35 @@ If there is something wrong, you can check the logs by: ``` $ rhc tail -a asdfasdf ``` + +Supported Ciphers +----------------- + +- rc4 +- null +- table +- bf-cfb +- rc2-cfb +- des-cfb +- idea-cfb +- seed-cfb +- cast5-cfb +- aes-256-cfb +- aes-128-cfb +- aes-192-cfb +- aes-256-ofb +- aes-128-ofb +- aes-192-ofb +- aes-128-ctr +- aes-192-ctr +- aes-256-ctr +- salsa20-ctr +- aes-128-cfb8 +- aes-192-cfb8 +- aes-256-cfb8 +- aes-128-cfb1 +- aes-192-cfb1 +- aes-256-cfb1 +- camellia-128-cfb +- camellia-192-cfb +- camellia-256-cfb From 0d1a7de2c6e16252ace0f22729bc4588559f5b85 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Fri, 23 Jan 2015 12:16:02 +0800 Subject: [PATCH 29/76] Specify `binary` sub-protocol only. Close #7. OpenShift WebSocket proxy returns vabatim `Sec-WebSocket-Protocol` header from upgrade request. --- local.js | 2 +- src/local.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/local.js b/local.js index 826dc0d1..3bfd5eaf 100644 --- a/local.js +++ b/local.js @@ -187,7 +187,7 @@ buf.writeInt16BE(remotePort, 8); connection.write(buf); ws = new WebSocket(aServer, { - protocol: "binary, base64" + protocol: "binary" }); ws.on("open", function() { var addrToSendBuf, i, piece; diff --git a/src/local.coffee b/src/local.coffee index 5adcdb2a..d563c61a 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -138,7 +138,7 @@ server = net.createServer (connection) -> buf.writeInt16BE remotePort, 8 connection.write buf # connect to remote server - ws = new WebSocket aServer, protocol: "binary, base64" + ws = new WebSocket aServer, protocol: "binary" ws.on "open", -> console.log "connecting #{remoteAddr} via #{aServer}" addrToSendBuf = new Buffer(addrToSend, "binary") From 38e24aca241bcc233fa787e4e9a74017f57520ef Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Sat, 24 Jan 2015 15:01:37 +0800 Subject: [PATCH 30/76] Revert "Support `null` cipher." This reverts commit a3e10611a2c56622540f72c120884ebe9a2ee3f9. --- README.md | 1 - encrypt.js | 24 +++++++++--------------- local.js | 2 +- server.js | 2 +- src/encrypt.coffee | 24 +++++++++--------------- src/local.coffee | 2 +- src/server.coffee | 2 +- 7 files changed, 22 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index eb034cca..bb2fd063 100644 --- a/README.md +++ b/README.md @@ -174,7 +174,6 @@ Supported Ciphers ----------------- - rc4 -- null - table - bf-cfb - rc2-cfb diff --git a/encrypt.js b/encrypt.js index 0d3a81ad..b8c6eb38 100644 --- a/encrypt.js +++ b/encrypt.js @@ -59,33 +59,27 @@ function Encryptor(key, method) { var _ref; this.method = method; - if (this.method === null) { - return; - } else if (this.method === "table") { - _ref = getTable(key), this.encryptTable = _ref[0], this.decryptTable = _ref[1]; - } else { + if (this.method != null) { this.cipher = crypto.createCipher(this.method, key); this.decipher = crypto.createDecipher(this.method, key); + } else { + _ref = getTable(key), this.encryptTable = _ref[0], this.decryptTable = _ref[1]; } } Encryptor.prototype.encrypt = function(buf) { - if (this.method === null) { - return buf; - } else if (this.method === "table") { - return encrypt(this.encryptTable, buf); - } else { + if (this.method != null) { return this.cipher.update(buf); + } else { + return encrypt(this.encryptTable, buf); } }; Encryptor.prototype.decrypt = function(buf) { - if (this.method === null) { - return buf; - } else if (this.method === "table") { - return encrypt(this.decryptTable, buf); - } else { + if (this.method != null) { return this.decipher.update(buf); + } else { + return encrypt(this.decryptTable, buf); } }; diff --git a/local.js b/local.js index 3bfd5eaf..dbd5a316 100644 --- a/local.js +++ b/local.js @@ -65,7 +65,7 @@ timeout = Math.floor(config.timeout * 1000); - if ((METHOD != null) && ((_ref = METHOD.toLowerCase()) === "" || _ref === "null")) { + if ((_ref = METHOD.toLowerCase()) === "" || _ref === "null" || _ref === "table") { METHOD = null; } diff --git a/server.js b/server.js index 991cd0bb..02e01a3b 100644 --- a/server.js +++ b/server.js @@ -79,7 +79,7 @@ METHOD = config.method; - if ((METHOD != null) && ((_ref = METHOD.toLowerCase()) === "" || _ref === "null")) { + if ((_ref = METHOD.toLowerCase()) === "" || _ref === "null" || _ref === "table") { METHOD = null; } diff --git a/src/encrypt.coffee b/src/encrypt.coffee index 14650eea..d1e74fc0 100644 --- a/src/encrypt.coffee +++ b/src/encrypt.coffee @@ -45,29 +45,23 @@ encrypt = (table, buf) -> class Encryptor constructor: (key, @method) -> - if @method is null - return - else if @method == "table" - [@encryptTable, @decryptTable] = getTable(key) - else + if @method? @cipher = crypto.createCipher @method, key @decipher = crypto.createDecipher @method, key + else + [@encryptTable, @decryptTable] = getTable(key) encrypt: (buf) -> - if @method is null - buf - else if @method == "table" - encrypt @encryptTable, buf - else + if @method? @cipher.update(buf) + else + encrypt @encryptTable, buf decrypt: (buf) -> - if @method is null - buf - else if @method == "table" - encrypt @decryptTable, buf - else + if @method? @decipher.update(buf) + else + encrypt @decryptTable, buf exports.Encryptor = Encryptor exports.getTable = getTable diff --git a/src/local.coffee b/src/local.coffee index d563c61a..2727c60d 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -39,7 +39,7 @@ KEY = config.password METHOD = config.method timeout = Math.floor(config.timeout * 1000) -if METHOD? and (METHOD.toLowerCase() in ["", "null"]) +if METHOD.toLowerCase() in ["", "null", "table"] METHOD = null prepareServer = (address) -> diff --git a/src/server.coffee b/src/server.coffee index 7eb9450e..e2e78734 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -43,7 +43,7 @@ PORT = config.remote_port KEY = config.password METHOD = config.method -if METHOD? and (METHOD.toLowerCase() in ["", "null"]) +if METHOD.toLowerCase() in ["", "null", "table"] METHOD = null setInterval(-> From 882f62153d84615e7d529e8f2eca44fb9dad318f Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Sat, 24 Jan 2015 20:38:49 +0800 Subject: [PATCH 31/76] Support `rc4-md5` cipher. --- LICENSE | 2 +- README.md | 22 ++------ config.json | 2 +- encrypt.js | 131 +++++++++++++++++++++++++++++++++++++++++---- src/encrypt.coffee | 111 ++++++++++++++++++++++++++++++++++---- 5 files changed, 231 insertions(+), 37 deletions(-) diff --git a/LICENSE b/LICENSE index a2487bee..fddcde43 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) Copyright (c) 2014 Zhao Xiaohong -Copyright (c) 2012 clowwindy +Copyright (c) 2012-2014 clowwindy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index bb2fd063..384bfabe 100644 --- a/README.md +++ b/README.md @@ -174,29 +174,17 @@ Supported Ciphers ----------------- - rc4 +- rc4-md5 - table - bf-cfb -- rc2-cfb - des-cfb +- rc2-cfb - idea-cfb - seed-cfb - cast5-cfb -- aes-256-cfb - aes-128-cfb - aes-192-cfb -- aes-256-ofb -- aes-128-ofb -- aes-192-ofb -- aes-128-ctr -- aes-192-ctr -- aes-256-ctr -- salsa20-ctr -- aes-128-cfb8 -- aes-192-cfb8 -- aes-256-cfb8 -- aes-128-cfb1 -- aes-192-cfb1 -- aes-256-cfb1 -- camellia-128-cfb -- camellia-192-cfb +- aes-256-cfb - camellia-256-cfb +- camellia-192-cfb +- camellia-128-cfb diff --git a/config.json b/config.json index 26c9f8c6..b67fa459 100644 --- a/config.json +++ b/config.json @@ -6,5 +6,5 @@ "remote_port": 8080, "password": "`try*(^^$some^$%^complex>:<>?~password/", "timeout": 600, - "method": "rc4" + "method": "rc4-md5" } diff --git a/encrypt.js b/encrypt.js index b8c6eb38..0358e152 100644 --- a/encrypt.js +++ b/encrypt.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.8.0 (function() { - var Encryptor, cachedTables, crypto, encrypt, getTable, int32Max, merge_sort; + var EVP_BytesToKey, Encryptor, bytes_to_key_results, cachedTables, create_rc4_md5_cipher, crypto, getTable, int32Max, merge_sort, method_supported, substitute; crypto = require("crypto"); @@ -45,7 +45,7 @@ return result; }; - encrypt = function(table, buf) { + substitute = function(table, buf) { var i; i = 0; while (i < buf.length) { @@ -55,31 +55,144 @@ return buf; }; + bytes_to_key_results = {}; + + EVP_BytesToKey = function(password, key_len, iv_len) { + var count, d, data, i, iv, key, m, md5, ms; + if (bytes_to_key_results["" + password + ":" + key_len + ":" + iv_len]) { + return bytes_to_key_results["" + password + ":" + key_len + ":" + iv_len]; + } + m = []; + i = 0; + count = 0; + while (count < key_len + iv_len) { + md5 = crypto.createHash('md5'); + data = password; + if (i > 0) { + data = Buffer.concat([m[i - 1], password]); + } + md5.update(data); + d = md5.digest(); + m.push(d); + count += d.length; + i += 1; + } + ms = Buffer.concat(m); + key = ms.slice(0, key_len); + iv = ms.slice(key_len, key_len + iv_len); + bytes_to_key_results[password] = [key, iv]; + return [key, iv]; + }; + + method_supported = { + 'aes-128-cfb': [16, 16], + 'aes-192-cfb': [24, 16], + 'aes-256-cfb': [32, 16], + 'bf-cfb': [16, 8], + 'camellia-128-cfb': [16, 16], + 'camellia-192-cfb': [24, 16], + 'camellia-256-cfb': [32, 16], + 'cast5-cfb': [16, 8], + 'des-cfb': [8, 8], + 'idea-cfb': [16, 8], + 'rc2-cfb': [16, 8], + 'rc4': [16, 0], + 'rc4-md5': [16, 16], + 'seed-cfb': [16, 16] + }; + + create_rc4_md5_cipher = function(key, iv, op) { + var md5, rc4_key; + md5 = crypto.createHash('md5'); + md5.update(key); + md5.update(iv); + rc4_key = md5.digest(); + if (op === 1) { + return crypto.createCipheriv('rc4', rc4_key, ''); + } else { + return crypto.createDecipheriv('rc4', rc4_key, ''); + } + }; + Encryptor = (function() { function Encryptor(key, method) { var _ref; + this.key = key; this.method = method; + this.iv_sent = false; + if (this.method === 'table') { + this.method = null; + } if (this.method != null) { - this.cipher = crypto.createCipher(this.method, key); - this.decipher = crypto.createDecipher(this.method, key); + this.cipher = this.get_cipher(this.key, this.method, 1, crypto.randomBytes(32)); } else { - _ref = getTable(key), this.encryptTable = _ref[0], this.decryptTable = _ref[1]; + _ref = getTable(this.key), this.encryptTable = _ref[0], this.decryptTable = _ref[1]; } } + Encryptor.prototype.get_cipher_len = function(method) { + var m; + method = method.toLowerCase(); + m = method_supported[method]; + return m; + }; + + Encryptor.prototype.get_cipher = function(password, method, op, iv) { + var iv_, key, m, _ref; + method = method.toLowerCase(); + password = new Buffer(password, 'binary'); + m = this.get_cipher_len(method); + if (m != null) { + _ref = EVP_BytesToKey(password, m[0], m[1]), key = _ref[0], iv_ = _ref[1]; + if (iv == null) { + iv = iv_; + } + if (op === 1) { + this.cipher_iv = iv.slice(0, m[1]); + } + iv = iv.slice(0, m[1]); + if (method === 'rc4-md5') { + return create_rc4_md5_cipher(key, iv, op); + } else { + if (op === 1) { + return crypto.createCipheriv(method, key, iv); + } else { + return crypto.createDecipheriv(method, key, iv); + } + } + } + }; + Encryptor.prototype.encrypt = function(buf) { + var result; if (this.method != null) { - return this.cipher.update(buf); + result = this.cipher.update(buf); + if (this.iv_sent) { + return result; + } else { + this.iv_sent = true; + return Buffer.concat([this.cipher_iv, result]); + } } else { - return encrypt(this.encryptTable, buf); + return substitute(this.encryptTable, buf); } }; Encryptor.prototype.decrypt = function(buf) { + var decipher_iv, decipher_iv_len, result; if (this.method != null) { - return this.decipher.update(buf); + if (this.decipher == null) { + decipher_iv_len = this.get_cipher_len(this.method)[1]; + decipher_iv = buf.slice(0, decipher_iv_len); + this.decipher = this.get_cipher(this.key, this.method, 0, decipher_iv); + result = this.decipher.update(buf.slice(decipher_iv_len)); + return result; + } else { + result = this.decipher.update(buf); + return result; + } } else { - return encrypt(this.decryptTable, buf); + return substitute(this.decryptTable, buf); } }; diff --git a/src/encrypt.coffee b/src/encrypt.coffee index d1e74fc0..a37514b1 100644 --- a/src/encrypt.coffee +++ b/src/encrypt.coffee @@ -35,7 +35,7 @@ getTable = (key) -> cachedTables[key] = result result -encrypt = (table, buf) -> +substitute = (table, buf) -> i = 0 while i < buf.length @@ -43,25 +43,118 @@ encrypt = (table, buf) -> i++ buf +bytes_to_key_results = {} + +EVP_BytesToKey = (password, key_len, iv_len) -> + if bytes_to_key_results["#{password}:#{key_len}:#{iv_len}"] + return bytes_to_key_results["#{password}:#{key_len}:#{iv_len}"] + m = [] + i = 0 + count = 0 + while count < key_len + iv_len + md5 = crypto.createHash('md5') + data = password + if i > 0 + data = Buffer.concat([m[i - 1], password]) + md5.update(data) + d = md5.digest() + m.push(d) + count += d.length + i += 1 + ms = Buffer.concat(m) + key = ms.slice(0, key_len) + iv = ms.slice(key_len, key_len + iv_len) + bytes_to_key_results[password] = [key, iv] + return [key, iv] + + +method_supported = + 'aes-128-cfb': [16, 16] + 'aes-192-cfb': [24, 16] + 'aes-256-cfb': [32, 16] + 'bf-cfb': [16, 8] + 'camellia-128-cfb': [16, 16] + 'camellia-192-cfb': [24, 16] + 'camellia-256-cfb': [32, 16] + 'cast5-cfb': [16, 8] + 'des-cfb': [8, 8] + 'idea-cfb': [16, 8] + 'rc2-cfb': [16, 8] + 'rc4': [16, 0] + 'rc4-md5': [16, 16] + 'seed-cfb': [16, 16] + + +create_rc4_md5_cipher = (key, iv, op) -> + md5 = crypto.createHash('md5') + md5.update(key) + md5.update(iv) + rc4_key = md5.digest() + if op == 1 + return crypto.createCipheriv('rc4', rc4_key, '') + else + return crypto.createDecipheriv('rc4', rc4_key, '') + + class Encryptor - constructor: (key, @method) -> + constructor: (@key, @method) -> + @iv_sent = false + if @method == 'table' + @method = null if @method? - @cipher = crypto.createCipher @method, key - @decipher = crypto.createDecipher @method, key + @cipher = @get_cipher(@key, @method, 1, crypto.randomBytes(32)) else - [@encryptTable, @decryptTable] = getTable(key) + [@encryptTable, @decryptTable] = getTable(@key) + + get_cipher_len: (method) -> + method = method.toLowerCase() + m = method_supported[method] + return m + + get_cipher: (password, method, op, iv) -> + method = method.toLowerCase() + password = new Buffer(password, 'binary') + m = @get_cipher_len(method) + if m? + [key, iv_] = EVP_BytesToKey(password, m[0], m[1]) + if not iv? + iv = iv_ + if op == 1 + @cipher_iv = iv.slice(0, m[1]) + iv = iv.slice(0, m[1]) + if method == 'rc4-md5' + return create_rc4_md5_cipher(key, iv, op) + else + if op == 1 + return crypto.createCipheriv(method, key, iv) + else + return crypto.createDecipheriv(method, key, iv) encrypt: (buf) -> if @method? - @cipher.update(buf) + result = @cipher.update buf + if @iv_sent + return result + else + @iv_sent = true + return Buffer.concat([@cipher_iv, result]) else - encrypt @encryptTable, buf + substitute @encryptTable, buf decrypt: (buf) -> if @method? - @decipher.update(buf) + if not @decipher? + decipher_iv_len = @get_cipher_len(@method)[1] + decipher_iv = buf.slice(0, decipher_iv_len) + @decipher = @get_cipher(@key, @method, 0, decipher_iv) + result = @decipher.update(buf.slice(decipher_iv_len)) + return result + else + result = @decipher.update(buf) + return result else - encrypt @decryptTable, buf + substitute @decryptTable, buf + exports.Encryptor = Encryptor exports.getTable = getTable From d73b996f2df13ee84e3d26f07545e649e9f46573 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Wed, 28 Jan 2015 09:36:09 +0800 Subject: [PATCH 32/76] fix #8. --- local.js | 7 +++++++ src/local.coffee | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/local.js b/local.js index dbd5a316..155544d1 100644 --- a/local.js +++ b/local.js @@ -191,6 +191,13 @@ }); ws.on("open", function() { var addrToSendBuf, i, piece; + ws._socket.on("error", function(e) { + console.log("remote " + remoteAddr + ":" + remotePort + " " + e); + connection.destroy(); + return server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); + }); console.log("connecting " + remoteAddr + " via " + aServer); addrToSendBuf = new Buffer(addrToSend, "binary"); addrToSendBuf = encryptor.encrypt(addrToSendBuf); diff --git a/src/local.coffee b/src/local.coffee index 2727c60d..4c128460 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -140,6 +140,13 @@ server = net.createServer (connection) -> # connect to remote server ws = new WebSocket aServer, protocol: "binary" ws.on "open", -> + ws._socket.on "error", (e) -> + console.log "remote #{remoteAddr}:#{remotePort} #{e}" + connection.destroy() + server.getConnections (err, count) -> + console.log "concurrent connections:", count + return + console.log "connecting #{remoteAddr} via #{aServer}" addrToSendBuf = new Buffer(addrToSend, "binary") addrToSendBuf = encryptor.encrypt addrToSendBuf From 22f20ecb083ee3209d4c2b18e7997aa0604f4d19 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 15 Oct 2015 18:21:55 +0800 Subject: [PATCH 33/76] Build with CoffeeScript 1.10.0 --- encrypt.js | 20 ++++++++++---------- local.js | 24 ++++++++++++------------ merge_sort.js | 2 +- server.js | 12 ++++++------ test.js | 2 +- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/encrypt.js b/encrypt.js index 0358e152..1b60dc22 100644 --- a/encrypt.js +++ b/encrypt.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.8.0 +// Generated by CoffeeScript 1.10.0 (function() { var EVP_BytesToKey, Encryptor, bytes_to_key_results, cachedTables, create_rc4_md5_cipher, crypto, getTable, int32Max, merge_sort, method_supported, substitute; @@ -59,8 +59,8 @@ EVP_BytesToKey = function(password, key_len, iv_len) { var count, d, data, i, iv, key, m, md5, ms; - if (bytes_to_key_results["" + password + ":" + key_len + ":" + iv_len]) { - return bytes_to_key_results["" + password + ":" + key_len + ":" + iv_len]; + if (bytes_to_key_results[password + ":" + key_len + ":" + iv_len]) { + return bytes_to_key_results[password + ":" + key_len + ":" + iv_len]; } m = []; i = 0; @@ -115,10 +115,10 @@ }; Encryptor = (function() { - function Encryptor(key, method) { - var _ref; - this.key = key; - this.method = method; + function Encryptor(key1, method1) { + var ref; + this.key = key1; + this.method = method1; this.iv_sent = false; if (this.method === 'table') { this.method = null; @@ -126,7 +126,7 @@ if (this.method != null) { this.cipher = this.get_cipher(this.key, this.method, 1, crypto.randomBytes(32)); } else { - _ref = getTable(this.key), this.encryptTable = _ref[0], this.decryptTable = _ref[1]; + ref = getTable(this.key), this.encryptTable = ref[0], this.decryptTable = ref[1]; } } @@ -138,12 +138,12 @@ }; Encryptor.prototype.get_cipher = function(password, method, op, iv) { - var iv_, key, m, _ref; + var iv_, key, m, ref; method = method.toLowerCase(); password = new Buffer(password, 'binary'); m = this.get_cipher_len(method); if (m != null) { - _ref = EVP_BytesToKey(password, m[0], m[1]), key = _ref[0], iv_ = _ref[1]; + ref = EVP_BytesToKey(password, m[0], m[1]), key = ref[0], iv_ = ref[1]; if (iv == null) { iv = iv_; } diff --git a/local.js b/local.js index 155544d1..36ae365f 100644 --- a/local.js +++ b/local.js @@ -1,6 +1,6 @@ -// Generated by CoffeeScript 1.8.0 +// Generated by CoffeeScript 1.10.0 (function() { - var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SCHEME, SERVER, WebSocket, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, prepareServer, s, server, timeout, url, v, _ref; + var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SCHEME, SERVER, WebSocket, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, prepareServer, ref, s, server, timeout, url, v; net = require("net"); @@ -65,7 +65,7 @@ timeout = Math.floor(config.timeout * 1000); - if ((_ref = METHOD.toLowerCase()) === "" || _ref === "null" || _ref === "table") { + if ((ref = METHOD.toLowerCase()) === "" || ref === "null" || ref === "table") { METHOD = null; } @@ -88,13 +88,13 @@ if (SERVER instanceof Array) { SERVER = (function() { - var _i, _len, _results; - _results = []; - for (_i = 0, _len = SERVER.length; _i < _len; _i++) { - s = SERVER[_i]; - _results.push(prepareServer(s)); + var j, len, results; + results = []; + for (j = 0, len = SERVER.length; j < len; j++) { + s = SERVER[j]; + results.push(prepareServer(s)); } - return _results; + return results; })(); } else { SERVER = prepareServer(SERVER); @@ -132,7 +132,7 @@ addrToSend = ""; aServer = getServer(); connection.on("data", function(data) { - var addrtype, buf, cmd, e, reply, tempBuf; + var addrtype, buf, cmd, e, error, reply, tempBuf; if (stage === 5) { data = encryptor.encrypt(data); if (ws.readyState === WebSocket.OPEN) { @@ -247,8 +247,8 @@ buf = null; } return stage = 4; - } catch (_error) { - e = _error; + } catch (error) { + e = error; console.log(e); return connection.destroy(); } diff --git a/merge_sort.js b/merge_sort.js index 3ff5bd61..32d25545 100644 --- a/merge_sort.js +++ b/merge_sort.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.8.0 +// Generated by CoffeeScript 1.10.0 (function() { var merge, merge_sort; diff --git a/server.js b/server.js index 02e01a3b..c57f99f0 100644 --- a/server.js +++ b/server.js @@ -1,6 +1,6 @@ -// Generated by CoffeeScript 1.8.0 +// Generated by CoffeeScript 1.10.0 (function() { - var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, WebSocket, WebSocketServer, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, server, timeout, v, wss, _ref; + var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, WebSocket, WebSocketServer, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, ref, server, timeout, v, wss; net = require("net"); @@ -79,7 +79,7 @@ METHOD = config.method; - if ((_ref = METHOD.toLowerCase()) === "" || _ref === "null" || _ref === "table") { + if ((ref = METHOD.toLowerCase()) === "" || ref === "null" || ref === "table") { METHOD = null; } @@ -113,7 +113,7 @@ remoteAddr = null; remotePort = null; ws.on("message", function(data, flags) { - var addrtype, buf, e; + var addrtype, buf, e, error; data = encryptor.decrypt(data); if (stage === 5) { if (!remote.write(data)) { @@ -186,8 +186,8 @@ buf = null; } return stage = 4; - } catch (_error) { - e = _error; + } catch (error) { + e = error; console.warn(e); if (remote) { remote.destroy(); diff --git a/test.js b/test.js index 4e8db470..891376f3 100644 --- a/test.js +++ b/test.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.8.0 +// Generated by CoffeeScript 1.10.0 (function() { var child_process, curlRunning, encrypt, i, local, localReady, runCurl, server, serverReady, tables, target; From fe9223e5d399890e65824786fc17741149c3b478 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 15 Oct 2015 18:24:08 +0800 Subject: [PATCH 34/76] Remove `gc()` --- local.js | 6 ------ server.js | 6 ------ src/local.coffee | 5 ----- src/server.coffee | 5 ----- 4 files changed, 22 deletions(-) diff --git a/local.js b/local.js index 36ae365f..726a75cc 100644 --- a/local.js +++ b/local.js @@ -108,12 +108,6 @@ } }; - setInterval(function() { - if (global.gc) { - return gc(); - } - }, 1000); - server = net.createServer(function(connection) { var aServer, addrLen, addrToSend, cachedPieces, encryptor, headerLength, ping, remoteAddr, remotePort, stage, ws; console.log("local connected"); diff --git a/server.js b/server.js index c57f99f0..9773bfda 100644 --- a/server.js +++ b/server.js @@ -83,12 +83,6 @@ METHOD = null; } - setInterval(function() { - if (global.gc) { - return gc(); - } - }, 1000); - server = http.createServer(function(req, res) { res.writeHead(200, { 'Content-Type': 'text/plain' diff --git a/src/local.coffee b/src/local.coffee index 4c128460..f739a6f6 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -63,11 +63,6 @@ getServer = -> else SERVER -setInterval(-> - if global.gc - gc() -, 1000) - server = net.createServer (connection) -> console.log "local connected" server.getConnections (err, count) -> diff --git a/src/server.coffee b/src/server.coffee index e2e78734..ceb42fe4 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -46,11 +46,6 @@ METHOD = config.method if METHOD.toLowerCase() in ["", "null", "table"] METHOD = null -setInterval(-> - if global.gc - gc() -, 1000) - server = http.createServer (req, res) -> res.writeHead 200, 'Content-Type': 'text/plain' res.end("asdf.") From 61543a9713b0c886880bf16d426a02f6f2db67ee Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Fri, 16 Oct 2015 00:27:29 +0800 Subject: [PATCH 35/76] Upgrade dependencies. --- Procfile | 2 +- README.md | 14 +------------- package.json | 13 +++++++------ 3 files changed, 9 insertions(+), 20 deletions(-) diff --git a/Procfile b/Procfile index 2f83fb16..063b78f4 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: node --expose-gc server.js -b 0.0.0.0 +web: npm start diff --git a/README.md b/README.md index 384bfabe..9936bc68 100644 --- a/README.md +++ b/README.md @@ -45,19 +45,13 @@ Install project dependencies with `npm install`: ``` $ npm install … -minimist@1.1.0 node_modules/minimist - -ws@0.6.4 node_modules/ws -├── options@0.0.6 -├── ultron@1.0.1 -└── nan@1.4.1 ``` Then run: ``` $ node local.js -s still-tor-8707.herokuapp.com -l 1080 -m rc4 -k foobar -r 80 -server listening at { address: '0.0.0.0', family: 'IPv4', port: 1080 } +server listening at { address: '127.0.0.1', family: 'IPv4', port: 1080 } ``` Change proxy settings of your browser into: @@ -141,12 +135,6 @@ Install project dependencies with `npm install`: ``` $ npm install … -minimist@1.1.0 node_modules/minimist - -ws@0.6.4 node_modules/ws -├── options@0.0.6 -├── ultron@1.0.1 -└── nan@1.4.1 ``` Then run: diff --git a/package.json b/package.json index ca39d011..38eecd14 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,14 @@ { "name": "shadowsocks-heroku", - "version": "0.9.9", + "version": "0.9.10", "dependencies": { - "minimist": "^1.1.0", - "ws": "^0.6.5" + "minimist": "^1.2.0", + "ws": "^0.8.0" }, "engines": { - "node": "0.10.x", - "npm": ">= 1.0.0" + "node": "4.x" }, - "main": "--expose-gc server.js" + "scripts": { + "start": "node server.js -b 0.0.0.0" + } } From b8b5beb513aea7fbacdf69314c8cb4bb9338d4e1 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 26 Nov 2015 00:25:42 +0800 Subject: [PATCH 36/76] Removed OpenShift support. Close #22. --- .openshift/README.md | 3 - .openshift/action_hooks/README.md | 3 - .openshift/cron/README.cron | 27 --------- .openshift/cron/daily/.gitignore | 0 .openshift/cron/hourly/.gitignore | 0 .openshift/cron/minutely/.gitignore | 0 .openshift/cron/monthly/.gitignore | 0 .openshift/cron/weekly/README | 16 ----- .openshift/cron/weekly/chrono.dat | 1 - .openshift/cron/weekly/chronograph | 3 - .openshift/cron/weekly/jobs.allow | 12 ---- .openshift/cron/weekly/jobs.deny | 7 --- .openshift/markers/README.md | 3 - README.md | 92 +---------------------------- server.js | 8 --- src/server.coffee | 4 -- 16 files changed, 1 insertion(+), 178 deletions(-) delete mode 100644 .openshift/README.md delete mode 100644 .openshift/action_hooks/README.md delete mode 100644 .openshift/cron/README.cron delete mode 100644 .openshift/cron/daily/.gitignore delete mode 100644 .openshift/cron/hourly/.gitignore delete mode 100644 .openshift/cron/minutely/.gitignore delete mode 100644 .openshift/cron/monthly/.gitignore delete mode 100644 .openshift/cron/weekly/README delete mode 100644 .openshift/cron/weekly/chrono.dat delete mode 100755 .openshift/cron/weekly/chronograph delete mode 100644 .openshift/cron/weekly/jobs.allow delete mode 100644 .openshift/cron/weekly/jobs.deny delete mode 100644 .openshift/markers/README.md diff --git a/.openshift/README.md b/.openshift/README.md deleted file mode 100644 index 7ec66d79..00000000 --- a/.openshift/README.md +++ /dev/null @@ -1,3 +0,0 @@ -For information about .openshift directory, consult the documentation: - -http://openshift.github.io/documentation/oo_user_guide.html#the-openshift-directory diff --git a/.openshift/action_hooks/README.md b/.openshift/action_hooks/README.md deleted file mode 100644 index 54131958..00000000 --- a/.openshift/action_hooks/README.md +++ /dev/null @@ -1,3 +0,0 @@ -For information about action hooks, consult the documentation: - -http://openshift.github.io/documentation/oo_user_guide.html#action-hooks diff --git a/.openshift/cron/README.cron b/.openshift/cron/README.cron deleted file mode 100644 index ac77f787..00000000 --- a/.openshift/cron/README.cron +++ /dev/null @@ -1,27 +0,0 @@ -Run scripts or jobs on a periodic basis -======================================= -Any scripts or jobs added to the minutely, hourly, daily, weekly or monthly -directories will be run on a scheduled basis (frequency is as indicated by the -name of the directory) using run-parts. - -run-parts ignores any files that are hidden or dotfiles (.*) or backup -files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} - -The presence of two specially named files jobs.deny and jobs.allow controls -how run-parts executes your scripts/jobs. - jobs.deny ===> Prevents specific scripts or jobs from being executed. - jobs.allow ===> Only execute the named scripts or jobs (all other/non-named - scripts that exist in this directory are ignored). - -The principles of jobs.deny and jobs.allow are the same as those of cron.deny -and cron.allow and are described in detail at: - http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Deployment_Guide/ch-Automating_System_Tasks.html#s2-autotasks-cron-access - -See: man crontab or above link for more details and see the the weekly/ - directory for an example. - -PLEASE NOTE: The Cron cartridge must be installed in order to run the configured jobs. - -For more information about cron, consult the documentation: -http://openshift.github.io/documentation/oo_cartridge_guide.html#cron -http://openshift.github.io/documentation/oo_user_guide.html#cron diff --git a/.openshift/cron/daily/.gitignore b/.openshift/cron/daily/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/.openshift/cron/hourly/.gitignore b/.openshift/cron/hourly/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/.openshift/cron/minutely/.gitignore b/.openshift/cron/minutely/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/.openshift/cron/monthly/.gitignore b/.openshift/cron/monthly/.gitignore deleted file mode 100644 index e69de29b..00000000 diff --git a/.openshift/cron/weekly/README b/.openshift/cron/weekly/README deleted file mode 100644 index 7c3e659f..00000000 --- a/.openshift/cron/weekly/README +++ /dev/null @@ -1,16 +0,0 @@ -Run scripts or jobs on a weekly basis -===================================== -Any scripts or jobs added to this directory will be run on a scheduled basis -(weekly) using run-parts. - -run-parts ignores any files that are hidden or dotfiles (.*) or backup -files (*~ or *,) or named *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} and handles -the files named jobs.deny and jobs.allow specially. - -In this specific example, the chronograph script is the only script or job file -executed on a weekly basis (due to white-listing it in jobs.allow). And the -README and chrono.dat file are ignored either as a result of being black-listed -in jobs.deny or because they are NOT white-listed in the jobs.allow file. - -For more details, please see ../README.cron file. - diff --git a/.openshift/cron/weekly/chrono.dat b/.openshift/cron/weekly/chrono.dat deleted file mode 100644 index fc4abb87..00000000 --- a/.openshift/cron/weekly/chrono.dat +++ /dev/null @@ -1 +0,0 @@ -Time And Relative D...n In Execution (Open)Shift! diff --git a/.openshift/cron/weekly/chronograph b/.openshift/cron/weekly/chronograph deleted file mode 100755 index 61de949f..00000000 --- a/.openshift/cron/weekly/chronograph +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -echo "`date`: `cat $(dirname \"$0\")/chrono.dat`" diff --git a/.openshift/cron/weekly/jobs.allow b/.openshift/cron/weekly/jobs.allow deleted file mode 100644 index 8d32abc7..00000000 --- a/.openshift/cron/weekly/jobs.allow +++ /dev/null @@ -1,12 +0,0 @@ -# -# Script or job files listed in here (one entry per line) will be -# executed on a weekly-basis. -# -# Example: The chronograph script will be executed weekly but the README -# and chrono.dat files in this directory will be ignored. -# -# The README file is actually ignored due to the entry in the -# jobs.deny which is checked before jobs.allow (this file). -# -chronograph - diff --git a/.openshift/cron/weekly/jobs.deny b/.openshift/cron/weekly/jobs.deny deleted file mode 100644 index 73c94500..00000000 --- a/.openshift/cron/weekly/jobs.deny +++ /dev/null @@ -1,7 +0,0 @@ -# -# Any script or job files listed in here (one entry per line) will NOT be -# executed (read as ignored by run-parts). -# - -README - diff --git a/.openshift/markers/README.md b/.openshift/markers/README.md deleted file mode 100644 index 45814da3..00000000 --- a/.openshift/markers/README.md +++ /dev/null @@ -1,3 +0,0 @@ -For information about markers, consult the documentation: - -http://openshift.github.io/documentation/oo_user_guide.html#markers diff --git a/README.md b/README.md index 9936bc68..de2217a3 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ shadowsocks-heroku shadowsocks-heroku is a lightweight tunnel proxy which can help you get through firewalls. It is a port of [shadowsocks](https://github.com/clowwindy/shadowsocks), but through a different protocol. -shadowsocks-heroku uses WebSocket instead of raw sockets, so it can be deployed on [Heroku](https://www.heroku.com/) and [OpenShift](https://www.openshift.com/). +shadowsocks-heroku uses WebSocket instead of raw sockets, so it can be deployed on [Heroku](https://www.heroku.com/). Notice that the protocol is INCOMPATIBLE with the origin shadowsocks. @@ -68,96 +68,6 @@ If there is something wrong, you can check the logs by: $ heroku logs -t --app still-tor-8707 ``` -OpenShift ---------- - -### Usage - -``` -$ rhc app create asdfasdf nodejs-0.10 -Application Options -------------------- -Domain: qwert -Cartridges: nodejs-0.10 -Gear Size: default -Scaling: no - -Creating application 'asdfasdf' ... done -… - -Your application 'asdfasdf' is now available. - - URL: http://asdfasdf-qwert.rhcloud.com/ - SSH to: 54b5e30d4382ec020700010d@asdfasdf-qwert.rhcloud.com - Git remote: ssh://54b5e30d4382ec020700010d@asdfasdf-qwert.rhcloud.com/~/git/asdfasdf.git/ - Cloned to: …/shadowsocks-heroku/asdfasdf - -Run 'rhc show-app asdfasdf' for more details about your app. -``` - -Push the code to OpenShift. - -``` -$ git remote add openshift ssh://54b5e30d4382ec020700010d@asdfasdf-qwert.rhcloud.com/~/git/asdfasdf.git -$ git push openshift -f -… -remote: npm info ok -remote: Preparing build for deployment -remote: Deployment id is 5b7aa220 -remote: Activating deployment -remote: Starting NodeJS cartridge -remote: Tue Jan 13 2015 22:42:36 GMT-0500 (EST): Starting application 'asdfasdf' ... -remote: ------------------------- -remote: Git Post-Receive Result: success -remote: Activation status: success -remote: Deployment completed with status: success -To ssh://54b5e30d4382ec020700010d@asdfasdf-qwert.rhcloud.com/~/git/asdfasdf.git - + 641794d...a3e1061 master -> master (forced update) -``` - -Set a few configs: - -``` -$ rhc env set METHOD=rc4 KEY=foobar -a asdfasdf -Setting environment variable(s) ... done -``` - -Restart application: - -``` -$ rhc app restart -a asdfasdf -RESULT: -asdfasdf restarted -``` - -Install project dependencies with `npm install`: - -``` -$ npm install -… -``` - -Then run: - -``` -$ node local.js -m rc4 -k foobar -s 'wss://asdfasdf-qwert.rhcloud.com:8443' -server listening at { address: '127.0.0.1', family: 'IPv4', port: 1080 } -``` - -Change proxy settings of your browser into: - -``` -SOCKS5 127.0.0.1:1080 -``` - -### Troubleshooting - -If there is something wrong, you can check the logs by: - -``` -$ rhc tail -a asdfasdf -``` - Supported Ciphers ----------------- diff --git a/server.js b/server.js index 9773bfda..cb45dbb4 100644 --- a/server.js +++ b/server.js @@ -44,14 +44,6 @@ config = JSON.parse(configContent); - if (process.env.OPENSHIFT_NODEJS_IP) { - config['local_address'] = process.env.OPENSHIFT_NODEJS_IP; - } - - if (process.env.OPENSHIFT_NODEJS_PORT) { - config['remote_port'] = +process.env.OPENSHIFT_NODEJS_PORT; - } - if (process.env.PORT) { config['remote_port'] = +process.env.PORT; } diff --git a/src/server.coffee b/src/server.coffee index ceb42fe4..c9b65d7b 100644 --- a/src/server.coffee +++ b/src/server.coffee @@ -26,10 +26,6 @@ configFile = configFromArgs.config_file configContent = fs.readFileSync(configFile) config = JSON.parse(configContent) -# OpenShift -config['local_address'] = process.env.OPENSHIFT_NODEJS_IP if process.env.OPENSHIFT_NODEJS_IP -config['remote_port'] = +process.env.OPENSHIFT_NODEJS_PORT if process.env.OPENSHIFT_NODEJS_PORT -# Heroku config['remote_port'] = +process.env.PORT if process.env.PORT config['password'] = process.env.KEY if process.env.KEY config['method'] = process.env.METHOD if process.env.METHOD From ba248ff89484eae6c04daeb38d3d021413b9958d Mon Sep 17 00:00:00 2001 From: bigbagboom Date: Wed, 24 Aug 2016 19:03:43 +0800 Subject: [PATCH 37/76] Support local HTTP Proxy. * Update local.js * Update local.js * Update package.json * Update local.coffee * Update local.js --- local.js | 32 +++++++++++++++++++++++++++----- package.json | 3 ++- src/local.coffee | 34 +++++++++++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 7 deletions(-) diff --git a/local.js b/local.js index 726a75cc..2752c93a 100644 --- a/local.js +++ b/local.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript 1.10.0 (function() { - var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SCHEME, SERVER, WebSocket, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, prepareServer, ref, s, server, timeout, url, v; + var Encryptor, HTTPPROXY, HttpsProxyAgent, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SCHEME, SERVER, WebSocket, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, prepareServer, ref, s, server, timeout, url, v; net = require("net"); @@ -16,6 +16,8 @@ parseArgs = require("minimist"); + HttpsProxyAgent = require('https-proxy-agent'); + Encryptor = require("./encrypt").Encryptor; options = { @@ -69,6 +71,12 @@ METHOD = null; } + HTTPPROXY = process.env.http_proxy; + + if (HTTPPROXY) { + console.log("http proxy:", HTTPPROXY); + } + prepareServer = function(address) { var serverUrl; serverUrl = url.parse(address); @@ -126,7 +134,7 @@ addrToSend = ""; aServer = getServer(); connection.on("data", function(data) { - var addrtype, buf, cmd, e, error, reply, tempBuf; + var addrtype, agent, buf, cmd, e, endpoint, error, opts, parsed, ref1, reply, tempBuf; if (stage === 5) { data = encryptor.encrypt(data); if (ws.readyState === WebSocket.OPEN) { @@ -180,9 +188,23 @@ buf.write("\u0000\u0000\u0000\u0000", 4, 4, "binary"); buf.writeInt16BE(remotePort, 8); connection.write(buf); - ws = new WebSocket(aServer, { - protocol: "binary" - }); + if (HTTPPROXY) { + endpoint = aServer; + parsed = url.parse(endpoint); + opts = url.parse(HTTPPROXY); + opts.secureEndpoint = (ref1 = parsed.protocol) != null ? ref1 : parsed.protocol === { + 'wss:': false + }; + agent = new HttpsProxyAgent(opts); + ws = new WebSocket(aServer, { + protocol: "binary", + agent: agent + }); + } else { + ws = new WebSocket(aServer, { + protocol: "binary" + }); + } ws.on("open", function() { var addrToSendBuf, i, piece; ws._socket.on("error", function(e) { diff --git a/package.json b/package.json index 38eecd14..0d211bb3 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,8 @@ "version": "0.9.10", "dependencies": { "minimist": "^1.2.0", - "ws": "^0.8.0" + "https-proxy-agent": "^1.0.0", + "ws": "^1.0.1" }, "engines": { "node": "4.x" diff --git a/src/local.coffee b/src/local.coffee index f739a6f6..7795a1a8 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -5,6 +5,7 @@ fs = require("fs") path = require("path") WebSocket = require('ws') parseArgs = require("minimist") +HttpsProxyAgent = require('https-proxy-agent') Encryptor = require("./encrypt").Encryptor options = @@ -41,6 +42,12 @@ timeout = Math.floor(config.timeout * 1000) if METHOD.toLowerCase() in ["", "null", "table"] METHOD = null + +HTTPPROXY = process.env.http_proxy + +if HTTPPROXY + console.log "http proxy:", HTTPPROXY + prepareServer = (address) -> serverUrl = url.parse address @@ -133,7 +140,32 @@ server = net.createServer (connection) -> buf.writeInt16BE remotePort, 8 connection.write buf # connect to remote server - ws = new WebSocket aServer, protocol: "binary" + # ws = new WebSocket aServer, protocol: "binary" + + if HTTPPROXY + # WebSocket endpoint for the proxy to connect to + endpoint = aServer + parsed = url.parse(endpoint) + #console.log('attempting to connect to WebSocket %j', endpoint); + + # create an instance of the `HttpsProxyAgent` class with the proxy server information + opts = url.parse(HTTPPROXY) + + # IMPORTANT! Set the `secureEndpoint` option to `false` when connecting + # over "ws://", but `true` when connecting over "wss://" + opts.secureEndpoint = parsed.protocol ? parsed.protocol == 'wss:' : false + + agent = new HttpsProxyAgent(opts) + + ws = new WebSocket(aServer, { + protocol: "binary", + agent: agent + }); + else + ws = new WebSocket(aServer, { + protocol: "binary" + }); + ws.on "open", -> ws._socket.on "error", (e) -> console.log "remote #{remoteAddr}:#{remotePort} #{e}" From 190f3c0c1262c7461fadf688915edc35164221cd Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Mon, 19 Jun 2017 10:57:41 +0800 Subject: [PATCH 38/76] Default Node to the latest Long-Term-Support release --- package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/package.json b/package.json index 0d211bb3..2b02d1c4 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,6 @@ "https-proxy-agent": "^1.0.0", "ws": "^1.0.1" }, - "engines": { - "node": "4.x" - }, "scripts": { "start": "node server.js -b 0.0.0.0" } From 5b4328ff23e6c731b63e4a787b2db3158ad9da9d Mon Sep 17 00:00:00 2001 From: denosawr Date: Fri, 15 Dec 2017 09:39:41 +0800 Subject: [PATCH 39/76] Fixed RangeError error due to signed vs unsigned int. --- local.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local.js b/local.js index 2752c93a..d3cc19af 100644 --- a/local.js +++ b/local.js @@ -186,7 +186,7 @@ buf = new Buffer(10); buf.write("\u0005\u0000\u0000\u0001", 0, 4, "binary"); buf.write("\u0000\u0000\u0000\u0000", 4, 4, "binary"); - buf.writeInt16BE(remotePort, 8); + buf.writeUInt16BE(remotePort, 8); connection.write(buf); if (HTTPPROXY) { endpoint = aServer; From 478e776b19a454249a604b2d50aacb62a5f5c9d5 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Wed, 3 Jan 2018 18:18:21 +0800 Subject: [PATCH 40/76] Minor. --- src/local.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/local.coffee b/src/local.coffee index 7795a1a8..f26901d3 100644 --- a/src/local.coffee +++ b/src/local.coffee @@ -137,7 +137,7 @@ server = net.createServer (connection) -> buf = new Buffer(10) buf.write "\u0005\u0000\u0000\u0001", 0, 4, "binary" buf.write "\u0000\u0000\u0000\u0000", 4, 4, "binary" - buf.writeInt16BE remotePort, 8 + buf.writeUInt16BE remotePort, 8 connection.write buf # connect to remote server # ws = new WebSocket aServer, protocol: "binary" From c1f434b7abbffb6f8c080c29cf4975ba9967d730 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Wed, 3 Jan 2018 18:26:01 +0800 Subject: [PATCH 41/76] CoffeeScript 2.1.1 --- encrypt.js | 39 ++++++++++++++++++--------------------- local.js | 38 ++++++++++++++++++++++++++++++-------- merge_sort.js | 2 +- server.js | 19 +++++++++++++------ test.js | 4 +++- 5 files changed, 65 insertions(+), 37 deletions(-) diff --git a/encrypt.js b/encrypt.js index 1b60dc22..c477930b 100644 --- a/encrypt.js +++ b/encrypt.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.10.0 +// Generated by CoffeeScript 2.1.1 (function() { var EVP_BytesToKey, Encryptor, bytes_to_key_results, cachedTables, create_rc4_md5_cipher, crypto, getTable, int32Max, merge_sort, method_supported, substitute; @@ -8,7 +8,7 @@ int32Max = Math.pow(2, 32); - cachedTables = {}; + cachedTables = {}; // password: [encryptTable, decryptTable] getTable = function(key) { var ah, al, decrypt_table, hash, i, md5sum, result, table; @@ -59,8 +59,8 @@ EVP_BytesToKey = function(password, key_len, iv_len) { var count, d, data, i, iv, key, m, md5, ms; - if (bytes_to_key_results[password + ":" + key_len + ":" + iv_len]) { - return bytes_to_key_results[password + ":" + key_len + ":" + iv_len]; + if (bytes_to_key_results[`${password}:${key_len}:${iv_len}`]) { + return bytes_to_key_results[`${password}:${key_len}:${iv_len}`]; } m = []; i = 0; @@ -114,9 +114,8 @@ } }; - Encryptor = (function() { - function Encryptor(key1, method1) { - var ref; + Encryptor = class Encryptor { + constructor(key1, method1) { this.key = key1; this.method = method1; this.iv_sent = false; @@ -126,24 +125,24 @@ if (this.method != null) { this.cipher = this.get_cipher(this.key, this.method, 1, crypto.randomBytes(32)); } else { - ref = getTable(this.key), this.encryptTable = ref[0], this.decryptTable = ref[1]; + [this.encryptTable, this.decryptTable] = getTable(this.key); } } - Encryptor.prototype.get_cipher_len = function(method) { + get_cipher_len(method) { var m; method = method.toLowerCase(); m = method_supported[method]; return m; - }; + } - Encryptor.prototype.get_cipher = function(password, method, op, iv) { - var iv_, key, m, ref; + get_cipher(password, method, op, iv) { + var iv_, key, m; method = method.toLowerCase(); password = new Buffer(password, 'binary'); m = this.get_cipher_len(method); if (m != null) { - ref = EVP_BytesToKey(password, m[0], m[1]), key = ref[0], iv_ = ref[1]; + [key, iv_] = EVP_BytesToKey(password, m[0], m[1]); if (iv == null) { iv = iv_; } @@ -161,9 +160,9 @@ } } } - }; + } - Encryptor.prototype.encrypt = function(buf) { + encrypt(buf) { var result; if (this.method != null) { result = this.cipher.update(buf); @@ -176,9 +175,9 @@ } else { return substitute(this.encryptTable, buf); } - }; + } - Encryptor.prototype.decrypt = function(buf) { + decrypt(buf) { var decipher_iv, decipher_iv_len, result; if (this.method != null) { if (this.decipher == null) { @@ -194,11 +193,9 @@ } else { return substitute(this.decryptTable, buf); } - }; - - return Encryptor; + } - })(); + }; exports.Encryptor = Encryptor; diff --git a/local.js b/local.js index d3cc19af..66659ac2 100644 --- a/local.js +++ b/local.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.10.0 +// Generated by CoffeeScript 2.1.1 (function() { var Encryptor, HTTPPROXY, HttpsProxyAgent, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SCHEME, SERVER, WebSocket, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, prepareServer, ref, s, server, timeout, url, v; @@ -31,7 +31,7 @@ 'm': 'method' }, string: ['local_address', 'server', 'password', 'config_file', 'method', 'scheme'], - "default": { + default: { 'config_file': path.resolve(__dirname, "config.json") } }; @@ -134,8 +134,9 @@ addrToSend = ""; aServer = getServer(); connection.on("data", function(data) { - var addrtype, agent, buf, cmd, e, endpoint, error, opts, parsed, ref1, reply, tempBuf; + var addrtype, agent, buf, cmd, e, endpoint, opts, parsed, ref1, reply, tempBuf; if (stage === 5) { + // pipe sockets data = encryptor.encrypt(data); if (ws.readyState === WebSocket.OPEN) { ws.send(data, { @@ -156,6 +157,13 @@ } if (stage === 1) { try { + // +----+-----+-------+------+----------+----------+ + // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | + // +----+-----+-------+------+----------+----------+ + // | 1 | 1 | X'00' | 1 | Variable | 2 | + // +----+-----+-------+------+----------+----------+ + + //cmd and addrtype cmd = data[1]; addrtype = data[3]; if (cmd !== 1) { @@ -172,6 +180,7 @@ return; } addrToSend = data.slice(3, 4).toString("binary"); + // read address and port if (addrtype === 1) { remoteAddr = inetNtoa(data.slice(4, 8)); addrToSend += data.slice(4, 10).toString("binary"); @@ -188,10 +197,19 @@ buf.write("\u0000\u0000\u0000\u0000", 4, 4, "binary"); buf.writeUInt16BE(remotePort, 8); connection.write(buf); + // connect to remote server + // ws = new WebSocket aServer, protocol: "binary" if (HTTPPROXY) { + // WebSocket endpoint for the proxy to connect to endpoint = aServer; parsed = url.parse(endpoint); + //console.log('attempting to connect to WebSocket %j', endpoint); + + // create an instance of the `HttpsProxyAgent` class with the proxy server information opts = url.parse(HTTPPROXY); + + // IMPORTANT! Set the `secureEndpoint` option to `false` when connecting + // over "ws://", but `true` when connecting over "wss://" opts.secureEndpoint = (ref1 = parsed.protocol) != null ? ref1 : parsed.protocol === { 'wss:': false }; @@ -208,13 +226,13 @@ ws.on("open", function() { var addrToSendBuf, i, piece; ws._socket.on("error", function(e) { - console.log("remote " + remoteAddr + ":" + remotePort + " " + e); + console.log(`remote ${remoteAddr}:${remotePort} ${e}`); connection.destroy(); return server.getConnections(function(err, count) { console.log("concurrent connections:", count); }); }); - console.log("connecting " + remoteAddr + " via " + aServer); + console.log(`connecting ${remoteAddr} via ${aServer}`); addrToSendBuf = new Buffer(addrToSend, "binary"); addrToSendBuf = encryptor.encrypt(addrToSendBuf); ws.send(addrToSendBuf, { @@ -229,7 +247,7 @@ }); i++; } - cachedPieces = null; + cachedPieces = null; // save memory stage = 5; ping = setInterval(function() { return ws.ping("", null, true); @@ -250,7 +268,7 @@ return connection.destroy(); }); ws.on("error", function(e) { - console.log("remote " + remoteAddr + ":" + remotePort + " error: " + e); + console.log(`remote ${remoteAddr}:${remotePort} error: ${e}`); connection.destroy(); return server.getConnections(function(err, count) { console.log("concurrent connections:", count); @@ -265,6 +283,7 @@ return stage = 4; } catch (error) { e = error; + // may encounter index out of range console.log(e); return connection.destroy(); } @@ -274,6 +293,9 @@ } } }); + // remote server not connected + // cache received buffers + // make sure no data is lost connection.on("end", function() { console.log("local disconnected"); if (ws) { @@ -284,7 +306,7 @@ }); }); connection.on("error", function(e) { - console.log("local error: " + e); + console.log(`local error: ${e}`); if (ws) { ws.terminate(); } diff --git a/merge_sort.js b/merge_sort.js index 32d25545..b58fcd3d 100644 --- a/merge_sort.js +++ b/merge_sort.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.10.0 +// Generated by CoffeeScript 2.1.1 (function() { var merge, merge_sort; diff --git a/server.js b/server.js index cb45dbb4..01416f08 100644 --- a/server.js +++ b/server.js @@ -1,4 +1,4 @@ -// Generated by CoffeeScript 1.10.0 +// Generated by CoffeeScript 2.1.1 (function() { var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, WebSocket, WebSocketServer, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, ref, server, timeout, v, wss; @@ -27,7 +27,7 @@ 'm': 'method' }, string: ['local_address', 'password', 'method', 'config_file'], - "default": { + default: { 'config_file': path.resolve(__dirname, "config.json") } }; @@ -99,7 +99,7 @@ remoteAddr = null; remotePort = null; ws.on("message", function(data, flags) { - var addrtype, buf, e, error; + var addrtype, buf, e; data = encryptor.decrypt(data); if (stage === 5) { if (!remote.write(data)) { @@ -117,6 +117,7 @@ ws.close(); return; } + // read address and port if (addrtype === 1) { remoteAddr = inetNtoa(data.slice(1, 5)); remotePort = data.readUInt16BE(5); @@ -126,6 +127,7 @@ remotePort = data.readUInt16BE(2 + addrLen); headerLength = 2 + addrLen + 2; } + // connect remote server remote = net.connect(remotePort, remoteAddr, function() { var i, piece; console.log("connecting", remoteAddr); @@ -135,7 +137,7 @@ remote.write(piece); i++; } - cachedPieces = null; + cachedPieces = null; // save memory return stage = 5; }); remote.on("data", function(data) { @@ -158,7 +160,7 @@ }); remote.on("error", function(e) { ws.terminate(); - return console.log("remote: " + e); + return console.log(`remote: ${e}`); }); remote.setTimeout(timeout, function() { console.log("remote timeout"); @@ -166,6 +168,7 @@ return ws.close(); }); if (data.length > headerLength) { + // make sure no data is lost buf = new Buffer(data.length - headerLength); data.copy(buf, 0, headerLength); cachedPieces.push(buf); @@ -174,6 +177,7 @@ return stage = 4; } catch (error) { e = error; + // may encouter index out of range console.warn(e); if (remote) { remote.destroy(); @@ -186,6 +190,9 @@ } } }); + // remote server not connected + // cache received buffers + // make sure no data is lost ws.on("ping", function() { return ws.pong('', null, true); }); @@ -202,7 +209,7 @@ } }); return ws.on("error", function(e) { - console.warn("server: " + e); + console.warn(`server: ${e}`); console.log("concurrent connections:", wss.clients.length); if (remote) { return remote.destroy(); diff --git a/test.js b/test.js index 891376f3..02a507c1 100644 --- a/test.js +++ b/test.js @@ -1,5 +1,6 @@ -// Generated by CoffeeScript 1.10.0 +// Generated by CoffeeScript 2.1.1 (function() { + // test encryption var child_process, curlRunning, encrypt, i, local, localReady, runCurl, server, serverReady, tables, target; encrypt = require("./encrypt"); @@ -18,6 +19,7 @@ i++; } + // test proxy child_process = require('child_process'); local = child_process.spawn('node', ['local.js']); From 9308853c086453fe34ed04c8eefdd480068b7fca Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Wed, 3 Jan 2018 20:38:20 +0800 Subject: [PATCH 42/76] decaffeinate https://github.com/decaffeinate/decaffeinate --- encrypt.js | 363 +++++++++++++------------- local.js | 587 +++++++++++++++++++----------------------- merge_sort.js | 53 ++-- server.js | 389 +++++++++++++--------------- src/encrypt.coffee | 160 ------------ src/local.coffee | 259 ------------------- src/merge_sort.coffee | 15 -- src/server.coffee | 160 ------------ src/test.coffee | 75 ------ test.js | 162 ++++++------ 10 files changed, 720 insertions(+), 1503 deletions(-) delete mode 100644 src/encrypt.coffee delete mode 100644 src/local.coffee delete mode 100644 src/merge_sort.coffee delete mode 100644 src/server.coffee delete mode 100644 src/test.coffee diff --git a/encrypt.js b/encrypt.js index c477930b..cacbb7f2 100644 --- a/encrypt.js +++ b/encrypt.js @@ -1,204 +1,199 @@ -// Generated by CoffeeScript 2.1.1 -(function() { - var EVP_BytesToKey, Encryptor, bytes_to_key_results, cachedTables, create_rc4_md5_cipher, crypto, getTable, int32Max, merge_sort, method_supported, substitute; - - crypto = require("crypto"); - - merge_sort = require("./merge_sort").merge_sort; - - int32Max = Math.pow(2, 32); - - cachedTables = {}; // password: [encryptTable, decryptTable] - - getTable = function(key) { - var ah, al, decrypt_table, hash, i, md5sum, result, table; - if (cachedTables[key]) { - return cachedTables[key]; - } - console.log("calculating ciphers"); - table = new Array(256); - decrypt_table = new Array(256); - md5sum = crypto.createHash("md5"); - md5sum.update(key); - hash = new Buffer(md5sum.digest(), "binary"); - al = hash.readUInt32LE(0); - ah = hash.readUInt32LE(4); - i = 0; - while (i < 256) { - table[i] = i; - i++; - } - i = 1; - while (i < 1024) { - table = merge_sort(table, function(x, y) { - return ((ah % (x + i)) * int32Max + al) % (x + i) - ((ah % (y + i)) * int32Max + al) % (y + i); - }); - i++; - } - i = 0; - while (i < 256) { - decrypt_table[table[i]] = i; - ++i; +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const crypto = require("crypto"); +const { merge_sort } = require("./merge_sort"); +const int32Max = Math.pow(2, 32); + +const cachedTables = {}; // password: [encryptTable, decryptTable] + +const getTable = function(key) { + if (cachedTables[key]) { + return cachedTables[key]; + } + console.log("calculating ciphers"); + let table = new Array(256); + const decrypt_table = new Array(256); + const md5sum = crypto.createHash("md5"); + md5sum.update(key); + const hash = new Buffer(md5sum.digest(), "binary"); + const al = hash.readUInt32LE(0); + const ah = hash.readUInt32LE(4); + let i = 0; + + while (i < 256) { + table[i] = i; + i++; + } + i = 1; + + while (i < 1024) { + table = merge_sort(table, (x, y) => ((((ah % (x + i)) * int32Max) + al) % (x + i)) - ((((ah % (y + i)) * int32Max) + al) % (y + i))); + i++; + } + i = 0; + while (i < 256) { + decrypt_table[table[i]] = i; + ++i; + } + const result = [table, decrypt_table]; + cachedTables[key] = result; + return result; +}; + +const substitute = function(table, buf) { + let i = 0; + + while (i < buf.length) { + buf[i] = table[buf[i]]; + i++; + } + return buf; +}; + +const bytes_to_key_results = {}; + +const EVP_BytesToKey = function(password, key_len, iv_len) { + if (bytes_to_key_results[`${password}:${key_len}:${iv_len}`]) { + return bytes_to_key_results[`${password}:${key_len}:${iv_len}`]; + } + const m = []; + let i = 0; + let count = 0; + while (count < (key_len + iv_len)) { + const md5 = crypto.createHash('md5'); + let data = password; + if (i > 0) { + data = Buffer.concat([m[i - 1], password]); } - result = [table, decrypt_table]; - cachedTables[key] = result; - return result; - }; - - substitute = function(table, buf) { - var i; - i = 0; - while (i < buf.length) { - buf[i] = table[buf[i]]; - i++; + md5.update(data); + const d = md5.digest(); + m.push(d); + count += d.length; + i += 1; + } + const ms = Buffer.concat(m); + const key = ms.slice(0, key_len); + const iv = ms.slice(key_len, key_len + iv_len); + bytes_to_key_results[password] = [key, iv]; + return [key, iv]; +}; + + +const method_supported = { + 'aes-128-cfb': [16, 16], + 'aes-192-cfb': [24, 16], + 'aes-256-cfb': [32, 16], + 'bf-cfb': [16, 8], + 'camellia-128-cfb': [16, 16], + 'camellia-192-cfb': [24, 16], + 'camellia-256-cfb': [32, 16], + 'cast5-cfb': [16, 8], + 'des-cfb': [8, 8], + 'idea-cfb': [16, 8], + 'rc2-cfb': [16, 8], + 'rc4': [16, 0], + 'rc4-md5': [16, 16], + 'seed-cfb': [16, 16] +}; + + +const create_rc4_md5_cipher = function(key, iv, op) { + const md5 = crypto.createHash('md5'); + md5.update(key); + md5.update(iv); + const rc4_key = md5.digest(); + if (op === 1) { + return crypto.createCipheriv('rc4', rc4_key, ''); + } else { + return crypto.createDecipheriv('rc4', rc4_key, ''); + } +}; + + +class Encryptor { + constructor(key, method) { + this.key = key; + this.method = method; + this.iv_sent = false; + if (this.method === 'table') { + this.method = null; } - return buf; - }; - - bytes_to_key_results = {}; - - EVP_BytesToKey = function(password, key_len, iv_len) { - var count, d, data, i, iv, key, m, md5, ms; - if (bytes_to_key_results[`${password}:${key_len}:${iv_len}`]) { - return bytes_to_key_results[`${password}:${key_len}:${iv_len}`]; - } - m = []; - i = 0; - count = 0; - while (count < key_len + iv_len) { - md5 = crypto.createHash('md5'); - data = password; - if (i > 0) { - data = Buffer.concat([m[i - 1], password]); - } - md5.update(data); - d = md5.digest(); - m.push(d); - count += d.length; - i += 1; - } - ms = Buffer.concat(m); - key = ms.slice(0, key_len); - iv = ms.slice(key_len, key_len + iv_len); - bytes_to_key_results[password] = [key, iv]; - return [key, iv]; - }; - - method_supported = { - 'aes-128-cfb': [16, 16], - 'aes-192-cfb': [24, 16], - 'aes-256-cfb': [32, 16], - 'bf-cfb': [16, 8], - 'camellia-128-cfb': [16, 16], - 'camellia-192-cfb': [24, 16], - 'camellia-256-cfb': [32, 16], - 'cast5-cfb': [16, 8], - 'des-cfb': [8, 8], - 'idea-cfb': [16, 8], - 'rc2-cfb': [16, 8], - 'rc4': [16, 0], - 'rc4-md5': [16, 16], - 'seed-cfb': [16, 16] - }; - - create_rc4_md5_cipher = function(key, iv, op) { - var md5, rc4_key; - md5 = crypto.createHash('md5'); - md5.update(key); - md5.update(iv); - rc4_key = md5.digest(); - if (op === 1) { - return crypto.createCipheriv('rc4', rc4_key, ''); + if (this.method != null) { + this.cipher = this.get_cipher(this.key, this.method, 1, crypto.randomBytes(32)); } else { - return crypto.createDecipheriv('rc4', rc4_key, ''); + [this.encryptTable, this.decryptTable] = Array.from(getTable(this.key)); } - }; - - Encryptor = class Encryptor { - constructor(key1, method1) { - this.key = key1; - this.method = method1; - this.iv_sent = false; - if (this.method === 'table') { - this.method = null; + } + + get_cipher_len(method) { + method = method.toLowerCase(); + const m = method_supported[method]; + return m; + } + + get_cipher(password, method, op, iv) { + method = method.toLowerCase(); + password = new Buffer(password, 'binary'); + const m = this.get_cipher_len(method); + if (m != null) { + const [key, iv_] = Array.from(EVP_BytesToKey(password, m[0], m[1])); + if ((iv == null)) { + iv = iv_; } - if (this.method != null) { - this.cipher = this.get_cipher(this.key, this.method, 1, crypto.randomBytes(32)); - } else { - [this.encryptTable, this.decryptTable] = getTable(this.key); + if (op === 1) { + this.cipher_iv = iv.slice(0, m[1]); } - } - - get_cipher_len(method) { - var m; - method = method.toLowerCase(); - m = method_supported[method]; - return m; - } - - get_cipher(password, method, op, iv) { - var iv_, key, m; - method = method.toLowerCase(); - password = new Buffer(password, 'binary'); - m = this.get_cipher_len(method); - if (m != null) { - [key, iv_] = EVP_BytesToKey(password, m[0], m[1]); - if (iv == null) { - iv = iv_; - } + iv = iv.slice(0, m[1]); + if (method === 'rc4-md5') { + return create_rc4_md5_cipher(key, iv, op); + } else { if (op === 1) { - this.cipher_iv = iv.slice(0, m[1]); - } - iv = iv.slice(0, m[1]); - if (method === 'rc4-md5') { - return create_rc4_md5_cipher(key, iv, op); + return crypto.createCipheriv(method, key, iv); } else { - if (op === 1) { - return crypto.createCipheriv(method, key, iv); - } else { - return crypto.createDecipheriv(method, key, iv); - } + return crypto.createDecipheriv(method, key, iv); } } } + } - encrypt(buf) { - var result; - if (this.method != null) { - result = this.cipher.update(buf); - if (this.iv_sent) { - return result; - } else { - this.iv_sent = true; - return Buffer.concat([this.cipher_iv, result]); - } + encrypt(buf) { + if (this.method != null) { + const result = this.cipher.update(buf); + if (this.iv_sent) { + return result; } else { - return substitute(this.encryptTable, buf); + this.iv_sent = true; + return Buffer.concat([this.cipher_iv, result]); } + } else { + return substitute(this.encryptTable, buf); } - - decrypt(buf) { - var decipher_iv, decipher_iv_len, result; - if (this.method != null) { - if (this.decipher == null) { - decipher_iv_len = this.get_cipher_len(this.method)[1]; - decipher_iv = buf.slice(0, decipher_iv_len); - this.decipher = this.get_cipher(this.key, this.method, 0, decipher_iv); - result = this.decipher.update(buf.slice(decipher_iv_len)); - return result; - } else { - result = this.decipher.update(buf); - return result; - } + } + + decrypt(buf) { + if (this.method != null) { + let result; + if ((this.decipher == null)) { + const decipher_iv_len = this.get_cipher_len(this.method)[1]; + const decipher_iv = buf.slice(0, decipher_iv_len); + this.decipher = this.get_cipher(this.key, this.method, 0, decipher_iv); + result = this.decipher.update(buf.slice(decipher_iv_len)); + return result; } else { - return substitute(this.decryptTable, buf); + result = this.decipher.update(buf); + return result; } + } else { + return substitute(this.decryptTable, buf); } + } +} - }; - - exports.Encryptor = Encryptor; - - exports.getTable = getTable; -}).call(this); +exports.Encryptor = Encryptor; +exports.getTable = getTable; diff --git a/local.js b/local.js index 66659ac2..6607313c 100644 --- a/local.js +++ b/local.js @@ -1,344 +1,301 @@ -// Generated by CoffeeScript 2.1.1 -(function() { - var Encryptor, HTTPPROXY, HttpsProxyAgent, KEY, LOCAL_ADDRESS, METHOD, PORT, REMOTE_PORT, SCHEME, SERVER, WebSocket, config, configContent, configFromArgs, fs, getServer, http, inetNtoa, k, net, options, parseArgs, path, prepareServer, ref, s, server, timeout, url, v; - - net = require("net"); - - url = require("url"); - - http = require("http"); - - fs = require("fs"); - - path = require("path"); - - WebSocket = require('ws'); - - parseArgs = require("minimist"); - - HttpsProxyAgent = require('https-proxy-agent'); - - Encryptor = require("./encrypt").Encryptor; - - options = { - alias: { - 'b': 'local_address', - 'l': 'local_port', - 's': 'server', - 'r': 'remote_port', - 'k': 'password', - 'c': 'config_file', - 'm': 'method' - }, - string: ['local_address', 'server', 'password', 'config_file', 'method', 'scheme'], - default: { - 'config_file': path.resolve(__dirname, "config.json") - } - }; - - inetNtoa = function(buf) { - return buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3]; - }; - - configFromArgs = parseArgs(process.argv.slice(2), options); - - configContent = fs.readFileSync(configFromArgs.config_file); - - config = JSON.parse(configContent); - - for (k in configFromArgs) { - v = configFromArgs[k]; - config[k] = v; - } - - SCHEME = config.scheme; - - SERVER = config.server; - - REMOTE_PORT = config.remote_port; - - LOCAL_ADDRESS = config.local_address; - - PORT = config.local_port; - - KEY = config.password; - - METHOD = config.method; - - timeout = Math.floor(config.timeout * 1000); - - if ((ref = METHOD.toLowerCase()) === "" || ref === "null" || ref === "table") { - METHOD = null; +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS104: Avoid inline assignments + * DS204: Change includes calls to have a more natural evaluation order + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let needle; +const net = require("net"); +const url = require("url"); +const http = require("http"); +const fs = require("fs"); +const path = require("path"); +const WebSocket = require('ws'); +const parseArgs = require("minimist"); +const HttpsProxyAgent = require('https-proxy-agent'); +const { Encryptor } = require("./encrypt"); + +const options = { + alias: { + 'b': 'local_address', + 'l': 'local_port', + 's': 'server', + 'r': 'remote_port', + 'k': 'password', + 'c': 'config_file', + 'm': 'method' + }, + string: ['local_address', 'server', 'password', + 'config_file', 'method', 'scheme'], + default: { + 'config_file': path.resolve(__dirname, "config.json") } - - HTTPPROXY = process.env.http_proxy; - - if (HTTPPROXY) { - console.log("http proxy:", HTTPPROXY); +}; + +const inetNtoa = buf => buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3]; + +const configFromArgs = parseArgs(process.argv.slice(2), options); +const configContent = fs.readFileSync(configFromArgs.config_file); +const config = JSON.parse(configContent); +for (let k in configFromArgs) { + const v = configFromArgs[k]; + config[k] = v; +} + +const SCHEME = config.scheme; +let SERVER = config.server; +const REMOTE_PORT = config.remote_port; +const LOCAL_ADDRESS = config.local_address; +const PORT = config.local_port; +const KEY = config.password; +let METHOD = config.method; +const timeout = Math.floor(config.timeout * 1000); + +if ((needle = METHOD.toLowerCase(), ["", "null", "table"].includes(needle))) { + METHOD = null; +} + +const HTTPPROXY = process.env.http_proxy; + +if (HTTPPROXY) { + console.log("http proxy:", HTTPPROXY); +} + + +const prepareServer = function(address) { + const serverUrl = url.parse(address); + serverUrl.slashes = true; + if (serverUrl.protocol == null) { serverUrl.protocol = SCHEME; } + if (serverUrl.hostname === null) { + serverUrl.hostname = address; + serverUrl.pathname = '/'; } + if (serverUrl.port == null) { serverUrl.port = REMOTE_PORT; } + return url.format(serverUrl); +}; - prepareServer = function(address) { - var serverUrl; - serverUrl = url.parse(address); - serverUrl.slashes = true; - if (serverUrl.protocol == null) { - serverUrl.protocol = SCHEME; - } - if (serverUrl.hostname === null) { - serverUrl.hostname = address; - serverUrl.pathname = '/'; - } - if (serverUrl.port == null) { - serverUrl.port = REMOTE_PORT; - } - return url.format(serverUrl); - }; +if (SERVER instanceof Array) { + SERVER = (Array.from(SERVER).map((s) => prepareServer(s))); +} else { + SERVER = prepareServer(SERVER); +} +const getServer = function() { if (SERVER instanceof Array) { - SERVER = (function() { - var j, len, results; - results = []; - for (j = 0, len = SERVER.length; j < len; j++) { - s = SERVER[j]; - results.push(prepareServer(s)); - } - return results; - })(); + return SERVER[Math.floor(Math.random() * SERVER.length)]; } else { - SERVER = prepareServer(SERVER); + return SERVER; } +}; - getServer = function() { - if (SERVER instanceof Array) { - return SERVER[Math.floor(Math.random() * SERVER.length)]; - } else { - return SERVER; +var server = net.createServer(function(connection) { + console.log("local connected"); + server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); + const encryptor = new Encryptor(KEY, METHOD); + let stage = 0; + let headerLength = 0; + let cachedPieces = []; + let addrLen = 0; + let ws = null; + let ping = null; + let remoteAddr = null; + let remotePort = null; + let addrToSend = ""; + const aServer = getServer(); + connection.on("data", function(data) { + if (stage === 5) { + // pipe sockets + data = encryptor.encrypt(data); + if (ws.readyState === WebSocket.OPEN) { + ws.send(data, { binary: true }); + if (ws.bufferedAmount > 0) { connection.pause(); } + } + return; } - }; - - server = net.createServer(function(connection) { - var aServer, addrLen, addrToSend, cachedPieces, encryptor, headerLength, ping, remoteAddr, remotePort, stage, ws; - console.log("local connected"); - server.getConnections(function(err, count) { - console.log("concurrent connections:", count); - }); - encryptor = new Encryptor(KEY, METHOD); - stage = 0; - headerLength = 0; - cachedPieces = []; - addrLen = 0; - ws = null; - ping = null; - remoteAddr = null; - remotePort = null; - addrToSend = ""; - aServer = getServer(); - connection.on("data", function(data) { - var addrtype, agent, buf, cmd, e, endpoint, opts, parsed, ref1, reply, tempBuf; - if (stage === 5) { - // pipe sockets - data = encryptor.encrypt(data); - if (ws.readyState === WebSocket.OPEN) { - ws.send(data, { - binary: true - }); - if (ws.bufferedAmount > 0) { - connection.pause(); - } + if (stage === 0) { + const tempBuf = new Buffer(2); + tempBuf.write("\u0005\u0000", 0); + connection.write(tempBuf); + stage = 1; + return; + } + if (stage === 1) { + try { + // +----+-----+-------+------+----------+----------+ + // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | + // +----+-----+-------+------+----------+----------+ + // | 1 | 1 | X'00' | 1 | Variable | 2 | + // +----+-----+-------+------+----------+----------+ + + //cmd and addrtype + const cmd = data[1]; + const addrtype = data[3]; + if (cmd !== 1) { + console.log("unsupported cmd:", cmd); + const reply = new Buffer("\u0005\u0007\u0000\u0001", "binary"); + connection.end(reply); + return; } - return; - } - if (stage === 0) { - tempBuf = new Buffer(2); - tempBuf.write("\u0005\u0000", 0); - connection.write(tempBuf); - stage = 1; - return; - } - if (stage === 1) { - try { - // +----+-----+-------+------+----------+----------+ - // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | - // +----+-----+-------+------+----------+----------+ - // | 1 | 1 | X'00' | 1 | Variable | 2 | - // +----+-----+-------+------+----------+----------+ - - //cmd and addrtype - cmd = data[1]; - addrtype = data[3]; - if (cmd !== 1) { - console.log("unsupported cmd:", cmd); - reply = new Buffer("\u0005\u0007\u0000\u0001", "binary"); - connection.end(reply); - return; - } - if (addrtype === 3) { - addrLen = data[4]; - } else if (addrtype !== 1) { - console.log("unsupported addrtype:", addrtype); - connection.end(); - return; - } - addrToSend = data.slice(3, 4).toString("binary"); - // read address and port - if (addrtype === 1) { - remoteAddr = inetNtoa(data.slice(4, 8)); - addrToSend += data.slice(4, 10).toString("binary"); - remotePort = data.readUInt16BE(8); - headerLength = 10; - } else { - remoteAddr = data.slice(5, 5 + addrLen).toString("binary"); - addrToSend += data.slice(4, 5 + addrLen + 2).toString("binary"); - remotePort = data.readUInt16BE(5 + addrLen); - headerLength = 5 + addrLen + 2; - } - buf = new Buffer(10); - buf.write("\u0005\u0000\u0000\u0001", 0, 4, "binary"); - buf.write("\u0000\u0000\u0000\u0000", 4, 4, "binary"); - buf.writeUInt16BE(remotePort, 8); - connection.write(buf); - // connect to remote server - // ws = new WebSocket aServer, protocol: "binary" - if (HTTPPROXY) { - // WebSocket endpoint for the proxy to connect to - endpoint = aServer; - parsed = url.parse(endpoint); - //console.log('attempting to connect to WebSocket %j', endpoint); - - // create an instance of the `HttpsProxyAgent` class with the proxy server information - opts = url.parse(HTTPPROXY); - - // IMPORTANT! Set the `secureEndpoint` option to `false` when connecting - // over "ws://", but `true` when connecting over "wss://" - opts.secureEndpoint = (ref1 = parsed.protocol) != null ? ref1 : parsed.protocol === { - 'wss:': false - }; - agent = new HttpsProxyAgent(opts); - ws = new WebSocket(aServer, { - protocol: "binary", - agent: agent - }); - } else { - ws = new WebSocket(aServer, { - protocol: "binary" - }); - } - ws.on("open", function() { - var addrToSendBuf, i, piece; - ws._socket.on("error", function(e) { - console.log(`remote ${remoteAddr}:${remotePort} ${e}`); - connection.destroy(); - return server.getConnections(function(err, count) { - console.log("concurrent connections:", count); + if (addrtype === 3) { + addrLen = data[4]; + } else if (addrtype !== 1) { + console.log("unsupported addrtype:", addrtype); + connection.end(); + return; + } + addrToSend = data.slice(3, 4).toString("binary"); + // read address and port + if (addrtype === 1) { + remoteAddr = inetNtoa(data.slice(4, 8)); + addrToSend += data.slice(4, 10).toString("binary"); + remotePort = data.readUInt16BE(8); + headerLength = 10; + } else { + remoteAddr = data.slice(5, 5 + addrLen).toString("binary"); + addrToSend += data.slice(4, 5 + addrLen + 2).toString("binary"); + remotePort = data.readUInt16BE(5 + addrLen); + headerLength = 5 + addrLen + 2; + } + let buf = new Buffer(10); + buf.write("\u0005\u0000\u0000\u0001", 0, 4, "binary"); + buf.write("\u0000\u0000\u0000\u0000", 4, 4, "binary"); + buf.writeUInt16BE(remotePort, 8); + connection.write(buf); + // connect to remote server + // ws = new WebSocket aServer, protocol: "binary" + + if (HTTPPROXY) { + // WebSocket endpoint for the proxy to connect to + const endpoint = aServer; + const parsed = url.parse(endpoint); + //console.log('attempting to connect to WebSocket %j', endpoint); + + // create an instance of the `HttpsProxyAgent` class with the proxy server information + const opts = url.parse(HTTPPROXY); + + // IMPORTANT! Set the `secureEndpoint` option to `false` when connecting + // over "ws://", but `true` when connecting over "wss://" + opts.secureEndpoint = parsed.protocol != null ? parsed.protocol : parsed.protocol === {'wss:' : false}; + + const agent = new HttpsProxyAgent(opts); + + ws = new WebSocket(aServer, { + protocol: "binary", + agent }); - }); - console.log(`connecting ${remoteAddr} via ${aServer}`); - addrToSendBuf = new Buffer(addrToSend, "binary"); - addrToSendBuf = encryptor.encrypt(addrToSendBuf); - ws.send(addrToSendBuf, { - binary: true - }); - i = 0; - while (i < cachedPieces.length) { - piece = cachedPieces[i]; - piece = encryptor.encrypt(piece); - ws.send(piece, { - binary: true + } else { + ws = new WebSocket(aServer, { + protocol: "binary" }); - i++; - } - cachedPieces = null; // save memory - stage = 5; - ping = setInterval(function() { - return ws.ping("", null, true); - }, 50 * 1000); - ws._socket.on("drain", function() { - return connection.resume(); - }); - }); - ws.on("message", function(data, flags) { - data = encryptor.decrypt(data); - if (!connection.write(data)) { - return ws._socket.pause(); - } - }); - ws.on("close", function() { - clearInterval(ping); - console.log("remote disconnected"); - return connection.destroy(); - }); - ws.on("error", function(e) { - console.log(`remote ${remoteAddr}:${remotePort} error: ${e}`); + } + + ws.on("open", function() { + ws._socket.on("error", function(e) { + console.log(`remote ${remoteAddr}:${remotePort} ${e}`); connection.destroy(); return server.getConnections(function(err, count) { console.log("concurrent connections:", count); }); }); - if (data.length > headerLength) { - buf = new Buffer(data.length - headerLength); - data.copy(buf, 0, headerLength); - cachedPieces.push(buf); - buf = null; + + console.log(`connecting ${remoteAddr} via ${aServer}`); + let addrToSendBuf = new Buffer(addrToSend, "binary"); + addrToSendBuf = encryptor.encrypt(addrToSendBuf); + ws.send(addrToSendBuf, { binary: true }); + let i = 0; + + while (i < cachedPieces.length) { + let piece = cachedPieces[i]; + piece = encryptor.encrypt(piece); + ws.send(piece, { binary: true }); + i++; } - return stage = 4; - } catch (error) { - e = error; - // may encounter index out of range - console.log(e); + cachedPieces = null; // save memory + stage = 5; + + ping = setInterval(() => ws.ping("", null, true) + , 50 * 1000); + + ws._socket.on("drain", () => connection.resume()); + + }); + + ws.on("message", function(data, flags) { + data = encryptor.decrypt(data); + if (!connection.write(data)) { return ws._socket.pause(); } + }); + + ws.on("close", function() { + clearInterval(ping); + console.log("remote disconnected"); return connection.destroy(); + }); + + ws.on("error", function(e) { + console.log(`remote ${remoteAddr}:${remotePort} error: ${e}`); + connection.destroy(); + return server.getConnections(function(err, count) { + console.log("concurrent connections:", count); + }); + }); + + if (data.length > headerLength) { + buf = new Buffer(data.length - headerLength); + data.copy(buf, 0, headerLength); + cachedPieces.push(buf); + buf = null; } - } else { - if (stage === 4) { - return cachedPieces.push(data); - } - } - }); - // remote server not connected - // cache received buffers - // make sure no data is lost - connection.on("end", function() { - console.log("local disconnected"); - if (ws) { - ws.terminate(); - } - return server.getConnections(function(err, count) { - console.log("concurrent connections:", count); - }); - }); - connection.on("error", function(e) { - console.log(`local error: ${e}`); - if (ws) { - ws.terminate(); - } - return server.getConnections(function(err, count) { - console.log("concurrent connections:", count); - }); - }); - connection.on("drain", function() { - if (ws && ws._socket) { - return ws._socket.resume(); + return stage = 4; + } catch (error) { + // may encounter index out of range + const e = error; + console.log(e); + return connection.destroy(); } + } else if (stage === 4) { return cachedPieces.push(data); } + }); + // remote server not connected + // cache received buffers + // make sure no data is lost + + connection.on("end", function() { + console.log("local disconnected"); + if (ws) { ws.terminate(); } + return server.getConnections(function(err, count) { + console.log("concurrent connections:", count); }); - return connection.setTimeout(timeout, function() { - console.log("local timeout"); - connection.destroy(); - if (ws) { - return ws.terminate(); - } + }); + + connection.on("error", function(e){ + console.log(`local error: ${e}`); + if (ws) { ws.terminate(); } + return server.getConnections(function(err, count) { + console.log("concurrent connections:", count); }); }); - server.listen(PORT, LOCAL_ADDRESS, function() { - var address; - address = server.address(); - return console.log("server listening at", address); + connection.on("drain", function() { + if (ws && ws._socket) { return ws._socket.resume(); } }); - server.on("error", function(e) { - if (e.code === "EADDRINUSE") { - console.log("address in use, aborting"); - } - return process.exit(1); + return connection.setTimeout(timeout, function() { + console.log("local timeout"); + connection.destroy(); + if (ws) { return ws.terminate(); } }); +}); + +server.listen(PORT, LOCAL_ADDRESS, function() { + const address = server.address(); + return console.log("server listening at", address); +}); -}).call(this); +server.on("error", function(e) { + if (e.code === "EADDRINUSE") { console.log("address in use, aborting"); } + return process.exit(1); +}); diff --git a/merge_sort.js b/merge_sort.js index b58fcd3d..4a461327 100644 --- a/merge_sort.js +++ b/merge_sort.js @@ -1,35 +1,24 @@ -// Generated by CoffeeScript 2.1.1 -(function() { - var merge, merge_sort; - - merge = function(left, right, comparison) { - var result; - result = new Array(); - while ((left.length > 0) && (right.length > 0)) { - if (comparison(left[0], right[0]) <= 0) { - result.push(left.shift()); - } else { - result.push(right.shift()); - } - } - while (left.length > 0) { +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const merge = function(left, right, comparison) { + const result = new Array(); + while ((left.length > 0) && (right.length > 0)) { + if (comparison(left[0], right[0]) <= 0) { result.push(left.shift()); - } - while (right.length > 0) { + } else { result.push(right.shift()); } - return result; - }; - - merge_sort = function(array, comparison) { - var middle; - if (array.length < 2) { - return array; - } - middle = Math.ceil(array.length / 2); - return merge(merge_sort(array.slice(0, middle), comparison), merge_sort(array.slice(middle), comparison), comparison); - }; - - exports.merge_sort = merge_sort; - -}).call(this); + } + while (left.length > 0) { result.push(left.shift()); } + while (right.length > 0) { result.push(right.shift()); } + return result; +}; +var merge_sort = function(array, comparison) { + if (array.length < 2) { return array; } + const middle = Math.ceil(array.length / 2); + return merge(merge_sort(array.slice(0, middle), comparison), merge_sort(array.slice(middle), comparison), comparison); +}; +exports.merge_sort = merge_sort; diff --git a/server.js b/server.js index 01416f08..6acf5ad0 100644 --- a/server.js +++ b/server.js @@ -1,233 +1,190 @@ -// Generated by CoffeeScript 2.1.1 -(function() { - var Encryptor, KEY, LOCAL_ADDRESS, METHOD, PORT, WebSocket, WebSocketServer, config, configContent, configFile, configFromArgs, fs, http, inetNtoa, k, net, options, parseArgs, path, ref, server, timeout, v, wss; - - net = require("net"); - - fs = require("fs"); - - path = require("path"); - - http = require("http"); - - WebSocket = require('ws'); - - WebSocketServer = WebSocket.Server; - - parseArgs = require("minimist"); - - Encryptor = require("./encrypt").Encryptor; - - options = { - alias: { - 'b': 'local_address', - 'r': 'remote_port', - 'k': 'password', - 'c': 'config_file', - 'm': 'method' - }, - string: ['local_address', 'password', 'method', 'config_file'], - default: { - 'config_file': path.resolve(__dirname, "config.json") - } - }; - - inetNtoa = function(buf) { - return buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3]; - }; - - configFromArgs = parseArgs(process.argv.slice(2), options); - - configFile = configFromArgs.config_file; - - configContent = fs.readFileSync(configFile); - - config = JSON.parse(configContent); - - if (process.env.PORT) { - config['remote_port'] = +process.env.PORT; - } - - if (process.env.KEY) { - config['password'] = process.env.KEY; - } - - if (process.env.METHOD) { - config['method'] = process.env.METHOD; - } - - for (k in configFromArgs) { - v = configFromArgs[k]; - config[k] = v; +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS104: Avoid inline assignments + * DS204: Change includes calls to have a more natural evaluation order + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let needle; +const net = require("net"); +const fs = require("fs"); +const path = require("path"); +const http = require("http"); +const WebSocket = require('ws'); +const WebSocketServer = WebSocket.Server; +const parseArgs = require("minimist"); +const { Encryptor } = require("./encrypt"); + +const options = { + alias: { + 'b': 'local_address', + 'r': 'remote_port', + 'k': 'password', + 'c': 'config_file', + 'm': 'method' + }, + string: ['local_address', 'password', 'method', 'config_file'], + default: { + 'config_file': path.resolve(__dirname, "config.json") } +}; + +const inetNtoa = buf => buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3]; + +const configFromArgs = parseArgs(process.argv.slice(2), options); +const configFile = configFromArgs.config_file; +const configContent = fs.readFileSync(configFile); +const config = JSON.parse(configContent); + +if (process.env.PORT) { config['remote_port'] = +process.env.PORT; } +if (process.env.KEY) { config['password'] = process.env.KEY; } +if (process.env.METHOD) { config['method'] = process.env.METHOD; } + +for (let k in configFromArgs) { + const v = configFromArgs[k]; + config[k] = v; +} + +const timeout = Math.floor(config.timeout * 1000); +const LOCAL_ADDRESS = config.local_address; +const PORT = config.remote_port; +const KEY = config.password; +let METHOD = config.method; + +if ((needle = METHOD.toLowerCase(), ["", "null", "table"].includes(needle))) { + METHOD = null; +} + +const server = http.createServer(function(req, res) { + res.writeHead(200, {'Content-Type': 'text/plain'}); + return res.end("asdf."); +}); + +const wss = new WebSocketServer({server}); + +wss.on("connection", function(ws) { + console.log("server connected"); + console.log("concurrent connections:", wss.clients.length); + const encryptor = new Encryptor(KEY, METHOD); + let stage = 0; + let headerLength = 0; + let remote = null; + let cachedPieces = []; + let addrLen = 0; + let remoteAddr = null; + let remotePort = null; + ws.on("message", function(data, flags) { + data = encryptor.decrypt(data); + if (stage === 5) { + if (!remote.write(data)) { ws._socket.pause(); } + return; + } + if (stage === 0) { + try { + const addrtype = data[0]; + if (addrtype === 3) { + addrLen = data[1]; + } else if (addrtype !== 1) { + console.warn(`unsupported addrtype: ${addrtype}`); + ws.close(); + return; + } + // read address and port + if (addrtype === 1) { + remoteAddr = inetNtoa(data.slice(1, 5)); + remotePort = data.readUInt16BE(5); + headerLength = 7; + } else { + remoteAddr = data.slice(2, 2 + addrLen).toString("binary"); + remotePort = data.readUInt16BE(2 + addrLen); + headerLength = 2 + addrLen + 2; + } - timeout = Math.floor(config.timeout * 1000); - - LOCAL_ADDRESS = config.local_address; + // connect remote server + remote = net.connect(remotePort, remoteAddr, function() { + console.log("connecting", remoteAddr); + let i = 0; - PORT = config.remote_port; + while (i < cachedPieces.length) { + const piece = cachedPieces[i]; + remote.write(piece); + i++; + } + cachedPieces = null; // save memory + return stage = 5; + }); + remote.on("data", function(data) { + data = encryptor.encrypt(data); + if (ws.readyState === WebSocket.OPEN) { + ws.send(data, { binary: true }); + if (ws.bufferedAmount > 0) { remote.pause(); } + } + }); - KEY = config.password; + remote.on("end", function() { + ws.close(); + return console.log("remote disconnected"); + }); - METHOD = config.method; + remote.on("drain", () => ws._socket.resume()); - if ((ref = METHOD.toLowerCase()) === "" || ref === "null" || ref === "table") { - METHOD = null; - } + remote.on("error", function(e){ + ws.terminate(); + return console.log(`remote: ${e}`); + }); - server = http.createServer(function(req, res) { - res.writeHead(200, { - 'Content-Type': 'text/plain' - }); - return res.end("asdf."); + remote.setTimeout(timeout, function() { + console.log("remote timeout"); + remote.destroy(); + return ws.close(); + }); + + if (data.length > headerLength) { + // make sure no data is lost + let buf = new Buffer(data.length - headerLength); + data.copy(buf, 0, headerLength); + cachedPieces.push(buf); + buf = null; + } + return stage = 4; + } catch (error) { + // may encouter index out of range + const e = error; + console.warn(e); + if (remote) { remote.destroy(); } + return ws.close(); + } + } else if (stage === 4) { return cachedPieces.push(data); } }); + // remote server not connected + // cache received buffers + // make sure no data is lost + + ws.on("ping", () => ws.pong('', null, true)); - wss = new WebSocketServer({ - server: server + ws._socket.on("drain", function() { + if (stage === 5) { return remote.resume(); } }); - wss.on("connection", function(ws) { - var addrLen, cachedPieces, encryptor, headerLength, remote, remoteAddr, remotePort, stage; - console.log("server connected"); + ws.on("close", function() { + console.log("server disconnected"); console.log("concurrent connections:", wss.clients.length); - encryptor = new Encryptor(KEY, METHOD); - stage = 0; - headerLength = 0; - remote = null; - cachedPieces = []; - addrLen = 0; - remoteAddr = null; - remotePort = null; - ws.on("message", function(data, flags) { - var addrtype, buf, e; - data = encryptor.decrypt(data); - if (stage === 5) { - if (!remote.write(data)) { - ws._socket.pause(); - } - return; - } - if (stage === 0) { - try { - addrtype = data[0]; - if (addrtype === 3) { - addrLen = data[1]; - } else if (addrtype !== 1) { - console.warn("unsupported addrtype: " + addrtype); - ws.close(); - return; - } - // read address and port - if (addrtype === 1) { - remoteAddr = inetNtoa(data.slice(1, 5)); - remotePort = data.readUInt16BE(5); - headerLength = 7; - } else { - remoteAddr = data.slice(2, 2 + addrLen).toString("binary"); - remotePort = data.readUInt16BE(2 + addrLen); - headerLength = 2 + addrLen + 2; - } - // connect remote server - remote = net.connect(remotePort, remoteAddr, function() { - var i, piece; - console.log("connecting", remoteAddr); - i = 0; - while (i < cachedPieces.length) { - piece = cachedPieces[i]; - remote.write(piece); - i++; - } - cachedPieces = null; // save memory - return stage = 5; - }); - remote.on("data", function(data) { - data = encryptor.encrypt(data); - if (ws.readyState === WebSocket.OPEN) { - ws.send(data, { - binary: true - }); - if (ws.bufferedAmount > 0) { - remote.pause(); - } - } - }); - remote.on("end", function() { - ws.close(); - return console.log("remote disconnected"); - }); - remote.on("drain", function() { - return ws._socket.resume(); - }); - remote.on("error", function(e) { - ws.terminate(); - return console.log(`remote: ${e}`); - }); - remote.setTimeout(timeout, function() { - console.log("remote timeout"); - remote.destroy(); - return ws.close(); - }); - if (data.length > headerLength) { - // make sure no data is lost - buf = new Buffer(data.length - headerLength); - data.copy(buf, 0, headerLength); - cachedPieces.push(buf); - buf = null; - } - return stage = 4; - } catch (error) { - e = error; - // may encouter index out of range - console.warn(e); - if (remote) { - remote.destroy(); - } - return ws.close(); - } - } else { - if (stage === 4) { - return cachedPieces.push(data); - } - } - }); - // remote server not connected - // cache received buffers - // make sure no data is lost - ws.on("ping", function() { - return ws.pong('', null, true); - }); - ws._socket.on("drain", function() { - if (stage === 5) { - return remote.resume(); - } - }); - ws.on("close", function() { - console.log("server disconnected"); - console.log("concurrent connections:", wss.clients.length); - if (remote) { - return remote.destroy(); - } - }); - return ws.on("error", function(e) { - console.warn(`server: ${e}`); - console.log("concurrent connections:", wss.clients.length); - if (remote) { - return remote.destroy(); - } - }); + if (remote) { return remote.destroy(); } }); - server.listen(PORT, LOCAL_ADDRESS, function() { - var address; - address = server.address(); - return console.log("server listening at", address); + return ws.on("error", function(e) { + console.warn(`server: ${e}`); + console.log("concurrent connections:", wss.clients.length); + if (remote) { return remote.destroy(); } }); +}); - server.on("error", function(e) { - if (e.code === "EADDRINUSE") { - console.log("address in use, aborting"); - } - return process.exit(1); - }); +server.listen(PORT, LOCAL_ADDRESS, function() { + const address = server.address(); + return console.log("server listening at", address); +}); -}).call(this); +server.on("error", function(e) { + if (e.code === "EADDRINUSE") { console.log("address in use, aborting"); } + return process.exit(1); +}); diff --git a/src/encrypt.coffee b/src/encrypt.coffee deleted file mode 100644 index a37514b1..00000000 --- a/src/encrypt.coffee +++ /dev/null @@ -1,160 +0,0 @@ -crypto = require("crypto") -merge_sort = require("./merge_sort").merge_sort -int32Max = Math.pow(2, 32) - -cachedTables = {} # password: [encryptTable, decryptTable] - -getTable = (key) -> - if cachedTables[key] - return cachedTables[key] - console.log "calculating ciphers" - table = new Array(256) - decrypt_table = new Array(256) - md5sum = crypto.createHash("md5") - md5sum.update key - hash = new Buffer(md5sum.digest(), "binary") - al = hash.readUInt32LE(0) - ah = hash.readUInt32LE(4) - i = 0 - - while i < 256 - table[i] = i - i++ - i = 1 - - while i < 1024 - table = merge_sort(table, (x, y) -> - ((ah % (x + i)) * int32Max + al) % (x + i) - ((ah % (y + i)) * int32Max + al) % (y + i) - ) - i++ - i = 0 - while i < 256 - decrypt_table[table[i]] = i - ++i - result = [table, decrypt_table] - cachedTables[key] = result - result - -substitute = (table, buf) -> - i = 0 - - while i < buf.length - buf[i] = table[buf[i]] - i++ - buf - -bytes_to_key_results = {} - -EVP_BytesToKey = (password, key_len, iv_len) -> - if bytes_to_key_results["#{password}:#{key_len}:#{iv_len}"] - return bytes_to_key_results["#{password}:#{key_len}:#{iv_len}"] - m = [] - i = 0 - count = 0 - while count < key_len + iv_len - md5 = crypto.createHash('md5') - data = password - if i > 0 - data = Buffer.concat([m[i - 1], password]) - md5.update(data) - d = md5.digest() - m.push(d) - count += d.length - i += 1 - ms = Buffer.concat(m) - key = ms.slice(0, key_len) - iv = ms.slice(key_len, key_len + iv_len) - bytes_to_key_results[password] = [key, iv] - return [key, iv] - - -method_supported = - 'aes-128-cfb': [16, 16] - 'aes-192-cfb': [24, 16] - 'aes-256-cfb': [32, 16] - 'bf-cfb': [16, 8] - 'camellia-128-cfb': [16, 16] - 'camellia-192-cfb': [24, 16] - 'camellia-256-cfb': [32, 16] - 'cast5-cfb': [16, 8] - 'des-cfb': [8, 8] - 'idea-cfb': [16, 8] - 'rc2-cfb': [16, 8] - 'rc4': [16, 0] - 'rc4-md5': [16, 16] - 'seed-cfb': [16, 16] - - -create_rc4_md5_cipher = (key, iv, op) -> - md5 = crypto.createHash('md5') - md5.update(key) - md5.update(iv) - rc4_key = md5.digest() - if op == 1 - return crypto.createCipheriv('rc4', rc4_key, '') - else - return crypto.createDecipheriv('rc4', rc4_key, '') - - -class Encryptor - constructor: (@key, @method) -> - @iv_sent = false - if @method == 'table' - @method = null - if @method? - @cipher = @get_cipher(@key, @method, 1, crypto.randomBytes(32)) - else - [@encryptTable, @decryptTable] = getTable(@key) - - get_cipher_len: (method) -> - method = method.toLowerCase() - m = method_supported[method] - return m - - get_cipher: (password, method, op, iv) -> - method = method.toLowerCase() - password = new Buffer(password, 'binary') - m = @get_cipher_len(method) - if m? - [key, iv_] = EVP_BytesToKey(password, m[0], m[1]) - if not iv? - iv = iv_ - if op == 1 - @cipher_iv = iv.slice(0, m[1]) - iv = iv.slice(0, m[1]) - if method == 'rc4-md5' - return create_rc4_md5_cipher(key, iv, op) - else - if op == 1 - return crypto.createCipheriv(method, key, iv) - else - return crypto.createDecipheriv(method, key, iv) - - encrypt: (buf) -> - if @method? - result = @cipher.update buf - if @iv_sent - return result - else - @iv_sent = true - return Buffer.concat([@cipher_iv, result]) - else - substitute @encryptTable, buf - - decrypt: (buf) -> - if @method? - if not @decipher? - decipher_iv_len = @get_cipher_len(@method)[1] - decipher_iv = buf.slice(0, decipher_iv_len) - @decipher = @get_cipher(@key, @method, 0, decipher_iv) - result = @decipher.update(buf.slice(decipher_iv_len)) - return result - else - result = @decipher.update(buf) - return result - else - substitute @decryptTable, buf - - -exports.Encryptor = Encryptor -exports.getTable = getTable diff --git a/src/local.coffee b/src/local.coffee deleted file mode 100644 index f26901d3..00000000 --- a/src/local.coffee +++ /dev/null @@ -1,259 +0,0 @@ -net = require("net") -url = require("url") -http = require("http") -fs = require("fs") -path = require("path") -WebSocket = require('ws') -parseArgs = require("minimist") -HttpsProxyAgent = require('https-proxy-agent') -Encryptor = require("./encrypt").Encryptor - -options = - alias: - 'b': 'local_address' - 'l': 'local_port' - 's': 'server' - 'r': 'remote_port' - 'k': 'password', - 'c': 'config_file', - 'm': 'method' - string: ['local_address', 'server', 'password', - 'config_file', 'method', 'scheme'] - default: - 'config_file': path.resolve(__dirname, "config.json") - -inetNtoa = (buf) -> - buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3] - -configFromArgs = parseArgs process.argv.slice(2), options -configContent = fs.readFileSync(configFromArgs.config_file) -config = JSON.parse(configContent) -for k, v of configFromArgs - config[k] = v - -SCHEME = config.scheme -SERVER = config.server -REMOTE_PORT = config.remote_port -LOCAL_ADDRESS = config.local_address -PORT = config.local_port -KEY = config.password -METHOD = config.method -timeout = Math.floor(config.timeout * 1000) - -if METHOD.toLowerCase() in ["", "null", "table"] - METHOD = null - -HTTPPROXY = process.env.http_proxy - -if HTTPPROXY - console.log "http proxy:", HTTPPROXY - - -prepareServer = (address) -> - serverUrl = url.parse address - serverUrl.slashes = true - serverUrl.protocol ?= SCHEME - if serverUrl.hostname is null - serverUrl.hostname = address - serverUrl.pathname = '/' - serverUrl.port ?= REMOTE_PORT - url.format(serverUrl) - -if SERVER instanceof Array - SERVER = (prepareServer(s) for s in SERVER) -else - SERVER = prepareServer(SERVER) - -getServer = -> - if SERVER instanceof Array - SERVER[Math.floor(Math.random() * SERVER.length)] - else - SERVER - -server = net.createServer (connection) -> - console.log "local connected" - server.getConnections (err, count) -> - console.log "concurrent connections:", count - return - encryptor = new Encryptor(KEY, METHOD) - stage = 0 - headerLength = 0 - cachedPieces = [] - addrLen = 0 - ws = null - ping = null - remoteAddr = null - remotePort = null - addrToSend = "" - aServer = getServer() - connection.on "data", (data) -> - if stage is 5 - # pipe sockets - data = encryptor.encrypt data - if ws.readyState is WebSocket.OPEN - ws.send data, { binary: true } - connection.pause() if ws.bufferedAmount > 0 - return - if stage is 0 - tempBuf = new Buffer(2) - tempBuf.write "\u0005\u0000", 0 - connection.write tempBuf - stage = 1 - return - if stage is 1 - try - # +----+-----+-------+------+----------+----------+ - # |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | - # +----+-----+-------+------+----------+----------+ - # | 1 | 1 | X'00' | 1 | Variable | 2 | - # +----+-----+-------+------+----------+----------+ - - #cmd and addrtype - cmd = data[1] - addrtype = data[3] - unless cmd is 1 - console.log "unsupported cmd:", cmd - reply = new Buffer("\u0005\u0007\u0000\u0001", "binary") - connection.end reply - return - if addrtype is 3 - addrLen = data[4] - else unless addrtype is 1 - console.log "unsupported addrtype:", addrtype - connection.end() - return - addrToSend = data.slice(3, 4).toString("binary") - # read address and port - if addrtype is 1 - remoteAddr = inetNtoa(data.slice(4, 8)) - addrToSend += data.slice(4, 10).toString("binary") - remotePort = data.readUInt16BE(8) - headerLength = 10 - else - remoteAddr = data.slice(5, 5 + addrLen).toString("binary") - addrToSend += data.slice(4, 5 + addrLen + 2).toString("binary") - remotePort = data.readUInt16BE(5 + addrLen) - headerLength = 5 + addrLen + 2 - buf = new Buffer(10) - buf.write "\u0005\u0000\u0000\u0001", 0, 4, "binary" - buf.write "\u0000\u0000\u0000\u0000", 4, 4, "binary" - buf.writeUInt16BE remotePort, 8 - connection.write buf - # connect to remote server - # ws = new WebSocket aServer, protocol: "binary" - - if HTTPPROXY - # WebSocket endpoint for the proxy to connect to - endpoint = aServer - parsed = url.parse(endpoint) - #console.log('attempting to connect to WebSocket %j', endpoint); - - # create an instance of the `HttpsProxyAgent` class with the proxy server information - opts = url.parse(HTTPPROXY) - - # IMPORTANT! Set the `secureEndpoint` option to `false` when connecting - # over "ws://", but `true` when connecting over "wss://" - opts.secureEndpoint = parsed.protocol ? parsed.protocol == 'wss:' : false - - agent = new HttpsProxyAgent(opts) - - ws = new WebSocket(aServer, { - protocol: "binary", - agent: agent - }); - else - ws = new WebSocket(aServer, { - protocol: "binary" - }); - - ws.on "open", -> - ws._socket.on "error", (e) -> - console.log "remote #{remoteAddr}:#{remotePort} #{e}" - connection.destroy() - server.getConnections (err, count) -> - console.log "concurrent connections:", count - return - - console.log "connecting #{remoteAddr} via #{aServer}" - addrToSendBuf = new Buffer(addrToSend, "binary") - addrToSendBuf = encryptor.encrypt addrToSendBuf - ws.send addrToSendBuf, { binary: true } - i = 0 - - while i < cachedPieces.length - piece = cachedPieces[i] - piece = encryptor.encrypt piece - ws.send piece, { binary: true } - i++ - cachedPieces = null # save memory - stage = 5 - - ping = setInterval(-> - ws.ping "", null, true - , 50 * 1000) - - ws._socket.on "drain", -> - connection.resume() - - return - - ws.on "message", (data, flags) -> - data = encryptor.decrypt data - ws._socket.pause() unless connection.write(data) - - ws.on "close", -> - clearInterval ping - console.log "remote disconnected" - connection.destroy() - - ws.on "error", (e) -> - console.log "remote #{remoteAddr}:#{remotePort} error: #{e}" - connection.destroy() - server.getConnections (err, count) -> - console.log "concurrent connections:", count - return - - if data.length > headerLength - buf = new Buffer(data.length - headerLength) - data.copy buf, 0, headerLength - cachedPieces.push buf - buf = null - stage = 4 - catch e - # may encounter index out of range - console.log e - connection.destroy() - else cachedPieces.push data if stage is 4 - # remote server not connected - # cache received buffers - # make sure no data is lost - - connection.on "end", -> - console.log "local disconnected" - ws.terminate() if ws - server.getConnections (err, count) -> - console.log "concurrent connections:", count - return - - connection.on "error", (e)-> - console.log "local error: #{e}" - ws.terminate() if ws - server.getConnections (err, count) -> - console.log "concurrent connections:", count - return - - connection.on "drain", -> - ws._socket.resume() if ws and ws._socket - - connection.setTimeout timeout, -> - console.log "local timeout" - connection.destroy() - ws.terminate() if ws - -server.listen PORT, LOCAL_ADDRESS, -> - address = server.address() - console.log "server listening at", address - -server.on "error", (e) -> - console.log "address in use, aborting" if e.code is "EADDRINUSE" - process.exit 1 diff --git a/src/merge_sort.coffee b/src/merge_sort.coffee deleted file mode 100644 index c3bffe00..00000000 --- a/src/merge_sort.coffee +++ /dev/null @@ -1,15 +0,0 @@ -merge = (left, right, comparison) -> - result = new Array() - while (left.length > 0) and (right.length > 0) - if comparison(left[0], right[0]) <= 0 - result.push left.shift() - else - result.push right.shift() - result.push left.shift() while left.length > 0 - result.push right.shift() while right.length > 0 - result -merge_sort = (array, comparison) -> - return array if array.length < 2 - middle = Math.ceil(array.length / 2) - merge merge_sort(array.slice(0, middle), comparison), merge_sort(array.slice(middle), comparison), comparison -exports.merge_sort = merge_sort diff --git a/src/server.coffee b/src/server.coffee deleted file mode 100644 index c9b65d7b..00000000 --- a/src/server.coffee +++ /dev/null @@ -1,160 +0,0 @@ -net = require("net") -fs = require("fs") -path = require("path") -http = require("http") -WebSocket = require('ws') -WebSocketServer = WebSocket.Server -parseArgs = require("minimist") -Encryptor = require("./encrypt").Encryptor - -options = - alias: - 'b': 'local_address' - 'r': 'remote_port' - 'k': 'password', - 'c': 'config_file', - 'm': 'method' - string: ['local_address', 'password', 'method', 'config_file'] - default: - 'config_file': path.resolve(__dirname, "config.json") - -inetNtoa = (buf) -> - buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3] - -configFromArgs = parseArgs process.argv.slice(2), options -configFile = configFromArgs.config_file -configContent = fs.readFileSync(configFile) -config = JSON.parse(configContent) - -config['remote_port'] = +process.env.PORT if process.env.PORT -config['password'] = process.env.KEY if process.env.KEY -config['method'] = process.env.METHOD if process.env.METHOD - -for k, v of configFromArgs - config[k] = v - -timeout = Math.floor(config.timeout * 1000) -LOCAL_ADDRESS = config.local_address -PORT = config.remote_port -KEY = config.password -METHOD = config.method - -if METHOD.toLowerCase() in ["", "null", "table"] - METHOD = null - -server = http.createServer (req, res) -> - res.writeHead 200, 'Content-Type': 'text/plain' - res.end("asdf.") - -wss = new WebSocketServer server: server - -wss.on "connection", (ws) -> - console.log "server connected" - console.log "concurrent connections:", wss.clients.length - encryptor = new Encryptor(KEY, METHOD) - stage = 0 - headerLength = 0 - remote = null - cachedPieces = [] - addrLen = 0 - remoteAddr = null - remotePort = null - ws.on "message", (data, flags) -> - data = encryptor.decrypt data - if stage is 5 - ws._socket.pause() unless remote.write(data) - return - if stage is 0 - try - addrtype = data[0] - if addrtype is 3 - addrLen = data[1] - else unless addrtype is 1 - console.warn "unsupported addrtype: " + addrtype - ws.close() - return - # read address and port - if addrtype is 1 - remoteAddr = inetNtoa(data.slice(1, 5)) - remotePort = data.readUInt16BE(5) - headerLength = 7 - else - remoteAddr = data.slice(2, 2 + addrLen).toString("binary") - remotePort = data.readUInt16BE(2 + addrLen) - headerLength = 2 + addrLen + 2 - - # connect remote server - remote = net.connect(remotePort, remoteAddr, -> - console.log "connecting", remoteAddr - i = 0 - - while i < cachedPieces.length - piece = cachedPieces[i] - remote.write piece - i++ - cachedPieces = null # save memory - stage = 5 - ) - remote.on "data", (data) -> - data = encryptor.encrypt data - if ws.readyState is WebSocket.OPEN - ws.send data, { binary: true } - remote.pause() if ws.bufferedAmount > 0 - return - - remote.on "end", -> - ws.close() - console.log "remote disconnected" - - remote.on "drain", -> - ws._socket.resume() - - remote.on "error", (e)-> - ws.terminate() - console.log "remote: #{e}" - - remote.setTimeout timeout, -> - console.log "remote timeout" - remote.destroy() - ws.close() - - if data.length > headerLength - # make sure no data is lost - buf = new Buffer(data.length - headerLength) - data.copy buf, 0, headerLength - cachedPieces.push buf - buf = null - stage = 4 - catch e - # may encouter index out of range - console.warn e - remote.destroy() if remote - ws.close() - else cachedPieces.push data if stage is 4 - # remote server not connected - # cache received buffers - # make sure no data is lost - - ws.on "ping", -> - ws.pong '', null, true - - ws._socket.on "drain", -> - remote.resume() if stage is 5 - - ws.on "close", -> - console.log "server disconnected" - console.log "concurrent connections:", wss.clients.length - remote.destroy() if remote - - ws.on "error", (e) -> - console.warn "server: #{e}" - console.log "concurrent connections:", wss.clients.length - remote.destroy() if remote - -server.listen PORT, LOCAL_ADDRESS, -> - address = server.address() - console.log "server listening at", address - -server.on "error", (e) -> - console.log "address in use, aborting" if e.code is "EADDRINUSE" - process.exit 1 diff --git a/src/test.coffee b/src/test.coffee deleted file mode 100644 index e79432c7..00000000 --- a/src/test.coffee +++ /dev/null @@ -1,75 +0,0 @@ -# test encryption -encrypt = require("./encrypt") -target = [ - [ 60, 53, 84, 138, 217, 94, 88, 23, 39, 242, 219, 35, 12, 157, 165, 181, 255, 143, 83, 247, 162, 16, 31, 209, 190, 171, 115, 65, 38, 41, 21, 245, 236, 46, 121, 62, 166, 233, 44, 154, 153, 145, 230, 49, 128, 216, 173, 29, 241, 119, 64, 229, 194, 103, 131, 110, 26, 197, 218, 59, 204, 56, 27, 34, 141, 221, 149, 239, 192, 195, 24, 155, 170, 183, 11, 254, 213, 37, 137, 226, 75, 203, 55, 19, 72, 248, 22, 129, 33, 175, 178, 10, 198, 71, 77, 36, 113, 167, 48, 2, 117, 140, 142, 66, 199, 232, 243, 32, 123, 54, 51, 82, 57, 177, 87, 251, 150, 196, 133, 5, 253, 130, 8, 184, 14, 152, 231, 3, 186, 159, 76, 89, 228, 205, 156, 96, 163, 146, 18, 91, 132, 85, 80, 109, 172, 176, 105, 13, 50, 235, 127, 0, 189, 95, 98, 136, 250, 200, 108, 179, 211, 214, 106, 168, 78, 79, 74, 210, 30, 73, 201, 151, 208, 114, 101, 174, 92, 52, 120, 240, 15, 169, 220, 182, 81, 224, 43, 185, 40, 99, 180, 17, 212, 158, 42, 90, 9, 191, 45, 6, 25, 4, 222, 67, 126, 1, 116, 124, 206, 69, 61, 7, 68, 97, 202, 63, 244, 20, 28, 58, 93, 134, 104, 144, 227, 147, 102, 118, 135, 148, 47, 238, 86, 112, 122, 70, 107, 215, 100, 139, 223, 225, 164, 237, 111, 125, 207, 160, 187, 246, 234, 161, 188, 193, 249, 252 ], - [ 151, 205, 99, 127, 201, 119, 199, 211, 122, 196, 91, 74, 12, 147, 124, 180, 21, 191, 138, 83, 217, 30, 86, 7, 70, 200, 56, 62, 218, 47, 168, 22, 107, 88, 63, 11, 95, 77, 28, 8, 188, 29, 194, 186, 38, 198, 33, 230, 98, 43, 148, 110, 177, 1, 109, 82, 61, 112, 219, 59, 0, 210, 35, 215, 50, 27, 103, 203, 212, 209, 235, 93, 84, 169, 166, 80, 130, 94, 164, 165, 142, 184, 111, 18, 2, 141, 232, 114, 6, 131, 195, 139, 176, 220, 5, 153, 135, 213, 154, 189, 238, 174, 226, 53, 222, 146, 162, 236, 158, 143, 55, 244, 233, 96, 173, 26, 206, 100, 227, 49, 178, 34, 234, 108, 207, 245, 204, 150, 44, 87, 121, 54, 140, 118, 221, 228, 155, 78, 3, 239, 101, 64, 102, 17, 223, 41, 137, 225, 229, 66, 116, 171, 125, 40, 39, 71, 134, 13, 193, 129, 247, 251, 20, 136, 242, 14, 36, 97, 163, 181, 72, 25, 144, 46, 175, 89, 145, 113, 90, 159, 190, 15, 183, 73, 123, 187, 128, 248, 252, 152, 24, 197, 68, 253, 52, 69, 117, 57, 92, 104, 157, 170, 214, 81, 60, 133, 208, 246, 172, 23, 167, 160, 192, 76, 161, 237, 45, 4, 58, 10, 182, 65, 202, 240, 185, 241, 79, 224, 132, 51, 42, 126, 105, 37, 250, 149, 32, 243, 231, 67, 179, 48, 9, 106, 216, 31, 249, 19, 85, 254, 156, 115, 255, 120, 75, 16 ] -] -tables = encrypt.getTable("foobar!") -console.log JSON.stringify(tables) -i = 0 - -while i < 256 - console.assert tables[0][i] is target[0][i] - console.assert tables[1][i] is target[1][i] - i++ - -# test proxy - -child_process = require('child_process') -local = child_process.spawn('node', ['local.js']) -server = child_process.spawn('node', ['server.js']) - -curlRunning = false - -local.on 'exit', (code)-> - server.kill() - if !curlRunning - process.exit code - -server.on 'exit', (code)-> - local.kill() - if !curlRunning - process.exit code - -localReady = false -serverReady = false -curlRunning = false - -runCurl = -> - curlRunning = true - curl = child_process.spawn 'curl', ['-v', 'http://www.example.com/', '-L', '--socks5-hostname', '127.0.0.1:1080'] - curl.on 'exit', (code)-> - local.kill() - server.kill() - if code is 0 - console.log 'Test passed' - process.exit 0 - else - console.error 'Test failed' - process.exit code - - curl.stdout.on 'data', (data) -> - console.log data.toString() - - curl.stderr.on 'data', (data) -> - console.warn data.toString() - -local.stderr.on 'data', (data) -> - console.warn data.toString() - -server.stderr.on 'data', (data) -> - console.warn data.toString() - -local.stdout.on 'data', (data) -> - console.log data.toString() - if data.toString().indexOf('listening at') >= 0 - localReady = true - if localReady and serverReady and not curlRunning - runCurl() - -server.stdout.on 'data', (data) -> - console.log data.toString() - if data.toString().indexOf('listening at') >= 0 - serverReady = true - if localReady and serverReady and not curlRunning - runCurl() diff --git a/test.js b/test.js index 02a507c1..118cd8d5 100644 --- a/test.js +++ b/test.js @@ -1,102 +1,90 @@ -// Generated by CoffeeScript 2.1.1 -(function() { - // test encryption - var child_process, curlRunning, encrypt, i, local, localReady, runCurl, server, serverReady, tables, target; - - encrypt = require("./encrypt"); - - target = [[60, 53, 84, 138, 217, 94, 88, 23, 39, 242, 219, 35, 12, 157, 165, 181, 255, 143, 83, 247, 162, 16, 31, 209, 190, 171, 115, 65, 38, 41, 21, 245, 236, 46, 121, 62, 166, 233, 44, 154, 153, 145, 230, 49, 128, 216, 173, 29, 241, 119, 64, 229, 194, 103, 131, 110, 26, 197, 218, 59, 204, 56, 27, 34, 141, 221, 149, 239, 192, 195, 24, 155, 170, 183, 11, 254, 213, 37, 137, 226, 75, 203, 55, 19, 72, 248, 22, 129, 33, 175, 178, 10, 198, 71, 77, 36, 113, 167, 48, 2, 117, 140, 142, 66, 199, 232, 243, 32, 123, 54, 51, 82, 57, 177, 87, 251, 150, 196, 133, 5, 253, 130, 8, 184, 14, 152, 231, 3, 186, 159, 76, 89, 228, 205, 156, 96, 163, 146, 18, 91, 132, 85, 80, 109, 172, 176, 105, 13, 50, 235, 127, 0, 189, 95, 98, 136, 250, 200, 108, 179, 211, 214, 106, 168, 78, 79, 74, 210, 30, 73, 201, 151, 208, 114, 101, 174, 92, 52, 120, 240, 15, 169, 220, 182, 81, 224, 43, 185, 40, 99, 180, 17, 212, 158, 42, 90, 9, 191, 45, 6, 25, 4, 222, 67, 126, 1, 116, 124, 206, 69, 61, 7, 68, 97, 202, 63, 244, 20, 28, 58, 93, 134, 104, 144, 227, 147, 102, 118, 135, 148, 47, 238, 86, 112, 122, 70, 107, 215, 100, 139, 223, 225, 164, 237, 111, 125, 207, 160, 187, 246, 234, 161, 188, 193, 249, 252], [151, 205, 99, 127, 201, 119, 199, 211, 122, 196, 91, 74, 12, 147, 124, 180, 21, 191, 138, 83, 217, 30, 86, 7, 70, 200, 56, 62, 218, 47, 168, 22, 107, 88, 63, 11, 95, 77, 28, 8, 188, 29, 194, 186, 38, 198, 33, 230, 98, 43, 148, 110, 177, 1, 109, 82, 61, 112, 219, 59, 0, 210, 35, 215, 50, 27, 103, 203, 212, 209, 235, 93, 84, 169, 166, 80, 130, 94, 164, 165, 142, 184, 111, 18, 2, 141, 232, 114, 6, 131, 195, 139, 176, 220, 5, 153, 135, 213, 154, 189, 238, 174, 226, 53, 222, 146, 162, 236, 158, 143, 55, 244, 233, 96, 173, 26, 206, 100, 227, 49, 178, 34, 234, 108, 207, 245, 204, 150, 44, 87, 121, 54, 140, 118, 221, 228, 155, 78, 3, 239, 101, 64, 102, 17, 223, 41, 137, 225, 229, 66, 116, 171, 125, 40, 39, 71, 134, 13, 193, 129, 247, 251, 20, 136, 242, 14, 36, 97, 163, 181, 72, 25, 144, 46, 175, 89, 145, 113, 90, 159, 190, 15, 183, 73, 123, 187, 128, 248, 252, 152, 24, 197, 68, 253, 52, 69, 117, 57, 92, 104, 157, 170, 214, 81, 60, 133, 208, 246, 172, 23, 167, 160, 192, 76, 161, 237, 45, 4, 58, 10, 182, 65, 202, 240, 185, 241, 79, 224, 132, 51, 42, 126, 105, 37, 250, 149, 32, 243, 231, 67, 179, 48, 9, 106, 216, 31, 249, 19, 85, 254, 156, 115, 255, 120, 75, 16]]; - - tables = encrypt.getTable("foobar!"); - - console.log(JSON.stringify(tables)); - - i = 0; - - while (i < 256) { - console.assert(tables[0][i] === target[0][i]); - console.assert(tables[1][i] === target[1][i]); - i++; +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +// test encryption +const encrypt = require("./encrypt"); +const target = [ + [ 60, 53, 84, 138, 217, 94, 88, 23, 39, 242, 219, 35, 12, 157, 165, 181, 255, 143, 83, 247, 162, 16, 31, 209, 190, 171, 115, 65, 38, 41, 21, 245, 236, 46, 121, 62, 166, 233, 44, 154, 153, 145, 230, 49, 128, 216, 173, 29, 241, 119, 64, 229, 194, 103, 131, 110, 26, 197, 218, 59, 204, 56, 27, 34, 141, 221, 149, 239, 192, 195, 24, 155, 170, 183, 11, 254, 213, 37, 137, 226, 75, 203, 55, 19, 72, 248, 22, 129, 33, 175, 178, 10, 198, 71, 77, 36, 113, 167, 48, 2, 117, 140, 142, 66, 199, 232, 243, 32, 123, 54, 51, 82, 57, 177, 87, 251, 150, 196, 133, 5, 253, 130, 8, 184, 14, 152, 231, 3, 186, 159, 76, 89, 228, 205, 156, 96, 163, 146, 18, 91, 132, 85, 80, 109, 172, 176, 105, 13, 50, 235, 127, 0, 189, 95, 98, 136, 250, 200, 108, 179, 211, 214, 106, 168, 78, 79, 74, 210, 30, 73, 201, 151, 208, 114, 101, 174, 92, 52, 120, 240, 15, 169, 220, 182, 81, 224, 43, 185, 40, 99, 180, 17, 212, 158, 42, 90, 9, 191, 45, 6, 25, 4, 222, 67, 126, 1, 116, 124, 206, 69, 61, 7, 68, 97, 202, 63, 244, 20, 28, 58, 93, 134, 104, 144, 227, 147, 102, 118, 135, 148, 47, 238, 86, 112, 122, 70, 107, 215, 100, 139, 223, 225, 164, 237, 111, 125, 207, 160, 187, 246, 234, 161, 188, 193, 249, 252 ], + [ 151, 205, 99, 127, 201, 119, 199, 211, 122, 196, 91, 74, 12, 147, 124, 180, 21, 191, 138, 83, 217, 30, 86, 7, 70, 200, 56, 62, 218, 47, 168, 22, 107, 88, 63, 11, 95, 77, 28, 8, 188, 29, 194, 186, 38, 198, 33, 230, 98, 43, 148, 110, 177, 1, 109, 82, 61, 112, 219, 59, 0, 210, 35, 215, 50, 27, 103, 203, 212, 209, 235, 93, 84, 169, 166, 80, 130, 94, 164, 165, 142, 184, 111, 18, 2, 141, 232, 114, 6, 131, 195, 139, 176, 220, 5, 153, 135, 213, 154, 189, 238, 174, 226, 53, 222, 146, 162, 236, 158, 143, 55, 244, 233, 96, 173, 26, 206, 100, 227, 49, 178, 34, 234, 108, 207, 245, 204, 150, 44, 87, 121, 54, 140, 118, 221, 228, 155, 78, 3, 239, 101, 64, 102, 17, 223, 41, 137, 225, 229, 66, 116, 171, 125, 40, 39, 71, 134, 13, 193, 129, 247, 251, 20, 136, 242, 14, 36, 97, 163, 181, 72, 25, 144, 46, 175, 89, 145, 113, 90, 159, 190, 15, 183, 73, 123, 187, 128, 248, 252, 152, 24, 197, 68, 253, 52, 69, 117, 57, 92, 104, 157, 170, 214, 81, 60, 133, 208, 246, 172, 23, 167, 160, 192, 76, 161, 237, 45, 4, 58, 10, 182, 65, 202, 240, 185, 241, 79, 224, 132, 51, 42, 126, 105, 37, 250, 149, 32, 243, 231, 67, 179, 48, 9, 106, 216, 31, 249, 19, 85, 254, 156, 115, 255, 120, 75, 16 ] +]; +const tables = encrypt.getTable("foobar!"); +console.log(JSON.stringify(tables)); +let i = 0; + +while (i < 256) { + console.assert(tables[0][i] === target[0][i]); + console.assert(tables[1][i] === target[1][i]); + i++; +} + +// test proxy + +const child_process = require('child_process'); +const local = child_process.spawn('node', ['local.js']); +const server = child_process.spawn('node', ['server.js']); + +let curlRunning = false; + +local.on('exit', function(code){ + server.kill(); + if (!curlRunning) { + return process.exit(code); } +}); - // test proxy - child_process = require('child_process'); - - local = child_process.spawn('node', ['local.js']); - - server = child_process.spawn('node', ['server.js']); +server.on('exit', function(code){ + local.kill(); + if (!curlRunning) { + return process.exit(code); + } +}); - curlRunning = false; +let localReady = false; +let serverReady = false; +curlRunning = false; - local.on('exit', function(code) { - server.kill(); - if (!curlRunning) { - return process.exit(code); - } - }); - - server.on('exit', function(code) { +const runCurl = function() { + curlRunning = true; + const curl = child_process.spawn('curl', ['-v', 'http://www.example.com/', '-L', '--socks5-hostname', '127.0.0.1:1080']); + curl.on('exit', function(code){ local.kill(); - if (!curlRunning) { + server.kill(); + if (code === 0) { + console.log('Test passed'); + return process.exit(0); + } else { + console.error('Test failed'); return process.exit(code); } }); - localReady = false; - - serverReady = false; + curl.stdout.on('data', data => console.log(data.toString())); - curlRunning = false; + return curl.stderr.on('data', data => console.warn(data.toString())); +}; - runCurl = function() { - var curl; - curlRunning = true; - curl = child_process.spawn('curl', ['-v', 'http://www.example.com/', '-L', '--socks5-hostname', '127.0.0.1:1080']); - curl.on('exit', function(code) { - local.kill(); - server.kill(); - if (code === 0) { - console.log('Test passed'); - return process.exit(0); - } else { - console.error('Test failed'); - return process.exit(code); - } - }); - curl.stdout.on('data', function(data) { - return console.log(data.toString()); - }); - return curl.stderr.on('data', function(data) { - return console.warn(data.toString()); - }); - }; +local.stderr.on('data', data => console.warn(data.toString())); - local.stderr.on('data', function(data) { - return console.warn(data.toString()); - }); - - server.stderr.on('data', function(data) { - return console.warn(data.toString()); - }); +server.stderr.on('data', data => console.warn(data.toString())); - local.stdout.on('data', function(data) { - console.log(data.toString()); - if (data.toString().indexOf('listening at') >= 0) { - localReady = true; - if (localReady && serverReady && !curlRunning) { - return runCurl(); - } +local.stdout.on('data', function(data) { + console.log(data.toString()); + if (data.toString().indexOf('listening at') >= 0) { + localReady = true; + if (localReady && serverReady && !curlRunning) { + return runCurl(); } - }); - - server.stdout.on('data', function(data) { - console.log(data.toString()); - if (data.toString().indexOf('listening at') >= 0) { - serverReady = true; - if (localReady && serverReady && !curlRunning) { - return runCurl(); - } + } +}); + +server.stdout.on('data', function(data) { + console.log(data.toString()); + if (data.toString().indexOf('listening at') >= 0) { + serverReady = true; + if (localReady && serverReady && !curlRunning) { + return runCurl(); } - }); - -}).call(this); + } +}); From c35918b7f9d55df7a847b12d4c4821dd9cf615c8 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 4 Jan 2018 01:12:04 +0800 Subject: [PATCH 43/76] decaffeinate suggestions https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md --- .gitignore | 42 +++++++++++++++++++++++++++--- Cakefile | 34 ------------------------ LICENSE | 2 +- encrypt.js | 27 +++++++------------- local.js | 71 ++++++++++++++++++++++----------------------------- merge_sort.js | 5 ---- server.js | 47 +++++++++++++++------------------- test.js | 19 +++++--------- 8 files changed, 105 insertions(+), 142 deletions(-) delete mode 100644 Cakefile diff --git a/.gitignore b/.gitignore index d1d5c6dd..d1bed128 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,15 @@ # Logs logs *.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* # Runtime data pids *.pid *.seed +*.pid.lock # Directory for instrumented libs generated by jscoverage/JSCover lib-cov @@ -13,15 +17,45 @@ lib-cov # Coverage directory used by tools like istanbul coverage +# nyc test coverage +.nyc_output + # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt +# Bower dependency directory (https://bower.io/) +bower_components + # node-waf configuration .lock-wscript -# Compiled binary addons (http://nodejs.org/api/addons.html) +# Compiled binary addons (https://nodejs.org/api/addons.html) build/Release -# Dependency directory -# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- -node_modules +# Dependency directories +node_modules/ +jspm_packages/ + +# Typescript v1 declaration files +typings/ + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env + +# next.js build output +.next diff --git a/Cakefile b/Cakefile deleted file mode 100644 index cfaed85d..00000000 --- a/Cakefile +++ /dev/null @@ -1,34 +0,0 @@ -{spawn} = require 'child_process' - -build = (callback) -> - os = require 'os' - if os.platform() == 'win32' - coffeeCmd = 'coffee.cmd' - else - coffeeCmd = 'coffee' - coffee = spawn coffeeCmd, ['-c', '-o', '.', 'src'] - coffee.stderr.on 'data', (data) -> - process.stderr.write data.toString() - coffee.stdout.on 'data', (data) -> - console.log data.toString() - coffee.on 'exit', (code) -> - console.log 'build completed' - callback?() if code is 0 - process.exit code - -test = (callback) -> - os = require 'os' - coffee = spawn 'node', ['test.js'] - coffee.stderr.on 'data', (data) -> - process.stderr.write data.toString() - coffee.stdout.on 'data', (data) -> - console.log data.toString() - coffee.on 'exit', (code) -> - callback?() if code is 0 - process.exit code - -task 'build', 'Build ./ from src/', -> - build() - -task 'test', 'Run unit test', -> - test() diff --git a/LICENSE b/LICENSE index fddcde43..1e3525d8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ The MIT License (MIT) -Copyright (c) 2014 Zhao Xiaohong +Copyright (c) 2014-2018 Zhao Xiaohong Copyright (c) 2012-2014 clowwindy Permission is hereby granted, free of charge, to any person obtaining a copy diff --git a/encrypt.js b/encrypt.js index cacbb7f2..f8b77efa 100644 --- a/encrypt.js +++ b/encrypt.js @@ -1,10 +1,3 @@ -/* - * decaffeinate suggestions: - * DS101: Remove unnecessary use of Array.from - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ const crypto = require("crypto"); const { merge_sort } = require("./merge_sort"); const int32Max = Math.pow(2, 32); @@ -123,26 +116,25 @@ class Encryptor { if (this.method === 'table') { this.method = null; } - if (this.method != null) { + if (this.method) { this.cipher = this.get_cipher(this.key, this.method, 1, crypto.randomBytes(32)); } else { - [this.encryptTable, this.decryptTable] = Array.from(getTable(this.key)); + [this.encryptTable, this.decryptTable] = getTable(this.key); } } get_cipher_len(method) { method = method.toLowerCase(); - const m = method_supported[method]; - return m; + return method_supported[method]; } get_cipher(password, method, op, iv) { method = method.toLowerCase(); password = new Buffer(password, 'binary'); const m = this.get_cipher_len(method); - if (m != null) { - const [key, iv_] = Array.from(EVP_BytesToKey(password, m[0], m[1])); - if ((iv == null)) { + if (m) { + const [key, iv_] = EVP_BytesToKey(password, m[0], m[1]); + if (!iv) { iv = iv_; } if (op === 1) { @@ -162,7 +154,7 @@ class Encryptor { } encrypt(buf) { - if (this.method != null) { + if (this.method) { const result = this.cipher.update(buf); if (this.iv_sent) { return result; @@ -176,9 +168,9 @@ class Encryptor { } decrypt(buf) { - if (this.method != null) { + if (this.method) { let result; - if ((this.decipher == null)) { + if (!this.decipher) { const decipher_iv_len = this.get_cipher_len(this.method)[1]; const decipher_iv = buf.slice(0, decipher_iv_len); this.decipher = this.get_cipher(this.key, this.method, 0, decipher_iv); @@ -194,6 +186,5 @@ class Encryptor { } } - exports.Encryptor = Encryptor; exports.getTable = getTable; diff --git a/local.js b/local.js index 6607313c..ad2ca905 100644 --- a/local.js +++ b/local.js @@ -1,13 +1,3 @@ -/* - * decaffeinate suggestions: - * DS101: Remove unnecessary use of Array.from - * DS102: Remove unnecessary code created because of implicit returns - * DS104: Avoid inline assignments - * DS204: Change includes calls to have a more natural evaluation order - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -let needle; const net = require("net"); const url = require("url"); const http = require("http"); @@ -54,31 +44,30 @@ const KEY = config.password; let METHOD = config.method; const timeout = Math.floor(config.timeout * 1000); -if ((needle = METHOD.toLowerCase(), ["", "null", "table"].includes(needle))) { +if (["", "null", "table"].includes(METHOD.toLowerCase())) { METHOD = null; } - -const HTTPPROXY = process.env.http_proxy; + +const HTTPPROXY = process.env.http_proxy; if (HTTPPROXY) { console.log("http proxy:", HTTPPROXY); } - const prepareServer = function(address) { const serverUrl = url.parse(address); serverUrl.slashes = true; - if (serverUrl.protocol == null) { serverUrl.protocol = SCHEME; } - if (serverUrl.hostname === null) { + if (!serverUrl.protocol) { serverUrl.protocol = SCHEME; } + if (!serverUrl.hostname) { serverUrl.hostname = address; serverUrl.pathname = '/'; } - if (serverUrl.port == null) { serverUrl.port = REMOTE_PORT; } + if (!serverUrl.port) { serverUrl.port = REMOTE_PORT; } return url.format(serverUrl); }; if (SERVER instanceof Array) { - SERVER = (Array.from(SERVER).map((s) => prepareServer(s))); + SERVER = SERVER.map(s => prepareServer(s)); } else { SERVER = prepareServer(SERVER); } @@ -170,18 +159,18 @@ var server = net.createServer(function(connection) { // ws = new WebSocket aServer, protocol: "binary" if (HTTPPROXY) { - // WebSocket endpoint for the proxy to connect to + // WebSocket endpoint for the proxy to connect to const endpoint = aServer; const parsed = url.parse(endpoint); //console.log('attempting to connect to WebSocket %j', endpoint); - - // create an instance of the `HttpsProxyAgent` class with the proxy server information + + // create an instance of the `HttpsProxyAgent` class with the proxy server information const opts = url.parse(HTTPPROXY); - - // IMPORTANT! Set the `secureEndpoint` option to `false` when connecting - // over "ws://", but `true` when connecting over "wss://" - opts.secureEndpoint = parsed.protocol != null ? parsed.protocol : parsed.protocol === {'wss:' : false}; - + + // IMPORTANT! Set the `secureEndpoint` option to `false` when connecting + // over "ws://", but `true` when connecting over "wss://" + opts.secureEndpoint = parsed.protocol ? parsed.protocol == 'wss:' : false + const agent = new HttpsProxyAgent(opts); ws = new WebSocket(aServer, { @@ -193,12 +182,12 @@ var server = net.createServer(function(connection) { protocol: "binary" }); } - + ws.on("open", function() { ws._socket.on("error", function(e) { console.log(`remote ${remoteAddr}:${remotePort} ${e}`); connection.destroy(); - return server.getConnections(function(err, count) { + server.getConnections(function(err, count) { console.log("concurrent connections:", count); }); }); @@ -227,19 +216,19 @@ var server = net.createServer(function(connection) { ws.on("message", function(data, flags) { data = encryptor.decrypt(data); - if (!connection.write(data)) { return ws._socket.pause(); } + if (!connection.write(data)) { ws._socket.pause(); } }); ws.on("close", function() { clearInterval(ping); console.log("remote disconnected"); - return connection.destroy(); + connection.destroy(); }); ws.on("error", function(e) { console.log(`remote ${remoteAddr}:${remotePort} error: ${e}`); connection.destroy(); - return server.getConnections(function(err, count) { + server.getConnections(function(err, count) { console.log("concurrent connections:", count); }); }); @@ -250,14 +239,14 @@ var server = net.createServer(function(connection) { cachedPieces.push(buf); buf = null; } - return stage = 4; + stage = 4; } catch (error) { // may encounter index out of range const e = error; console.log(e); - return connection.destroy(); + connection.destroy(); } - } else if (stage === 4) { return cachedPieces.push(data); } + } else if (stage === 4) { cachedPieces.push(data); } }); // remote server not connected // cache received buffers @@ -266,7 +255,7 @@ var server = net.createServer(function(connection) { connection.on("end", function() { console.log("local disconnected"); if (ws) { ws.terminate(); } - return server.getConnections(function(err, count) { + server.getConnections(function(err, count) { console.log("concurrent connections:", count); }); }); @@ -274,28 +263,28 @@ var server = net.createServer(function(connection) { connection.on("error", function(e){ console.log(`local error: ${e}`); if (ws) { ws.terminate(); } - return server.getConnections(function(err, count) { + server.getConnections(function(err, count) { console.log("concurrent connections:", count); }); }); connection.on("drain", function() { - if (ws && ws._socket) { return ws._socket.resume(); } + if (ws && ws._socket) { ws._socket.resume(); } }); - return connection.setTimeout(timeout, function() { + connection.setTimeout(timeout, function() { console.log("local timeout"); connection.destroy(); - if (ws) { return ws.terminate(); } + if (ws) { ws.terminate(); } }); }); server.listen(PORT, LOCAL_ADDRESS, function() { const address = server.address(); - return console.log("server listening at", address); + console.log("server listening at", address); }); server.on("error", function(e) { if (e.code === "EADDRINUSE") { console.log("address in use, aborting"); } - return process.exit(1); + process.exit(1); }); diff --git a/merge_sort.js b/merge_sort.js index 4a461327..c0249c90 100644 --- a/merge_sort.js +++ b/merge_sort.js @@ -1,8 +1,3 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ const merge = function(left, right, comparison) { const result = new Array(); while ((left.length > 0) && (right.length > 0)) { diff --git a/server.js b/server.js index 6acf5ad0..d6078c31 100644 --- a/server.js +++ b/server.js @@ -1,11 +1,3 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS104: Avoid inline assignments - * DS204: Change includes calls to have a more natural evaluation order - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ -let needle; const net = require("net"); const fs = require("fs"); const path = require("path"); @@ -51,13 +43,13 @@ const PORT = config.remote_port; const KEY = config.password; let METHOD = config.method; -if ((needle = METHOD.toLowerCase(), ["", "null", "table"].includes(needle))) { +if (["", "null", "table"].includes(METHOD.toLowerCase())) { METHOD = null; } const server = http.createServer(function(req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); - return res.end("asdf."); + res.end("asdf."); }); const wss = new WebSocketServer({server}); @@ -77,7 +69,6 @@ wss.on("connection", function(ws) { data = encryptor.decrypt(data); if (stage === 5) { if (!remote.write(data)) { ws._socket.pause(); } - return; } if (stage === 0) { try { @@ -111,7 +102,7 @@ wss.on("connection", function(ws) { i++; } cachedPieces = null; // save memory - return stage = 5; + stage = 5; }); remote.on("data", function(data) { data = encryptor.encrypt(data); @@ -123,20 +114,20 @@ wss.on("connection", function(ws) { remote.on("end", function() { ws.close(); - return console.log("remote disconnected"); + console.log("remote disconnected"); }); remote.on("drain", () => ws._socket.resume()); remote.on("error", function(e){ ws.terminate(); - return console.log(`remote: ${e}`); + console.log(`remote: ${e}`); }); remote.setTimeout(timeout, function() { console.log("remote timeout"); remote.destroy(); - return ws.close(); + ws.close(); }); if (data.length > headerLength) { @@ -146,45 +137,47 @@ wss.on("connection", function(ws) { cachedPieces.push(buf); buf = null; } - return stage = 4; + stage = 4; } catch (error) { // may encouter index out of range const e = error; console.warn(e); if (remote) { remote.destroy(); } - return ws.close(); + ws.close(); } - } else if (stage === 4) { return cachedPieces.push(data); } + } else if (stage === 4) { + // remote server not connected + // cache received buffers + // make sure no data is lost + cachedPieces.push(data); + } }); - // remote server not connected - // cache received buffers - // make sure no data is lost ws.on("ping", () => ws.pong('', null, true)); ws._socket.on("drain", function() { - if (stage === 5) { return remote.resume(); } + if (stage === 5) { remote.resume(); } }); ws.on("close", function() { console.log("server disconnected"); console.log("concurrent connections:", wss.clients.length); - if (remote) { return remote.destroy(); } + if (remote) { remote.destroy(); } }); - return ws.on("error", function(e) { + ws.on("error", function(e) { console.warn(`server: ${e}`); console.log("concurrent connections:", wss.clients.length); - if (remote) { return remote.destroy(); } + if (remote) { remote.destroy(); } }); }); server.listen(PORT, LOCAL_ADDRESS, function() { const address = server.address(); - return console.log("server listening at", address); + console.log("server listening at", address); }); server.on("error", function(e) { if (e.code === "EADDRINUSE") { console.log("address in use, aborting"); } - return process.exit(1); + process.exit(1); }); diff --git a/test.js b/test.js index 118cd8d5..305c2504 100644 --- a/test.js +++ b/test.js @@ -1,8 +1,3 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ // test encryption const encrypt = require("./encrypt"); const target = [ @@ -30,14 +25,14 @@ let curlRunning = false; local.on('exit', function(code){ server.kill(); if (!curlRunning) { - return process.exit(code); + process.exit(code); } }); server.on('exit', function(code){ local.kill(); if (!curlRunning) { - return process.exit(code); + process.exit(code); } }); @@ -53,16 +48,16 @@ const runCurl = function() { server.kill(); if (code === 0) { console.log('Test passed'); - return process.exit(0); + process.exit(0); } else { console.error('Test failed'); - return process.exit(code); + process.exit(code); } }); curl.stdout.on('data', data => console.log(data.toString())); - return curl.stderr.on('data', data => console.warn(data.toString())); + curl.stderr.on('data', data => console.warn(data.toString())); }; local.stderr.on('data', data => console.warn(data.toString())); @@ -74,7 +69,7 @@ local.stdout.on('data', function(data) { if (data.toString().indexOf('listening at') >= 0) { localReady = true; if (localReady && serverReady && !curlRunning) { - return runCurl(); + runCurl(); } } }); @@ -84,7 +79,7 @@ server.stdout.on('data', function(data) { if (data.toString().indexOf('listening at') >= 0) { serverReady = true; if (localReady && serverReady && !curlRunning) { - return runCurl(); + runCurl(); } } }); From 3c31c446bd7ff3e08deeac326f46d80b11d4091b Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 4 Jan 2018 01:15:27 +0800 Subject: [PATCH 44/76] yarn --- package.json | 2 +- yarn.lock | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 yarn.lock diff --git a/package.json b/package.json index 2b02d1c4..b1250001 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,8 @@ "name": "shadowsocks-heroku", "version": "0.9.10", "dependencies": { - "minimist": "^1.2.0", "https-proxy-agent": "^1.0.0", + "minimist": "^1.2.0", "ws": "^1.0.1" }, "scripts": { diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..86e5d674 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,55 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +agent-base@2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" + dependencies: + extend "~3.0.0" + semver "~5.0.1" + +debug@2: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + dependencies: + ms "2.0.0" + +extend@3, extend@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +https-proxy-agent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" + dependencies: + agent-base "2" + debug "2" + extend "3" + +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +options@>=0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" + +semver@~5.0.1: + version "5.0.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" + +ultron@1.0.x: + version "1.0.2" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" + +ws@^1.0.1: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51" + dependencies: + options ">=0.0.5" + ultron "1.0.x" From c0fc97a1dac1289d947416772f56f0ceb4a7a9f2 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 4 Jan 2018 01:25:06 +0800 Subject: [PATCH 45/76] prettier --- encrypt.js | 31 +++++---- local.js | 178 +++++++++++++++++++++++++++++--------------------- merge_sort.js | 20 ++++-- server.js | 124 ++++++++++++++++++++--------------- test.js | 18 +++-- 5 files changed, 220 insertions(+), 151 deletions(-) diff --git a/encrypt.js b/encrypt.js index f8b77efa..183c5ab5 100644 --- a/encrypt.js +++ b/encrypt.js @@ -1,5 +1,5 @@ -const crypto = require("crypto"); -const { merge_sort } = require("./merge_sort"); +const crypto = require('crypto'); +const { merge_sort } = require('./merge_sort'); const int32Max = Math.pow(2, 32); const cachedTables = {}; // password: [encryptTable, decryptTable] @@ -8,12 +8,12 @@ const getTable = function(key) { if (cachedTables[key]) { return cachedTables[key]; } - console.log("calculating ciphers"); + console.log('calculating ciphers'); let table = new Array(256); const decrypt_table = new Array(256); - const md5sum = crypto.createHash("md5"); + const md5sum = crypto.createHash('md5'); md5sum.update(key); - const hash = new Buffer(md5sum.digest(), "binary"); + const hash = new Buffer(md5sum.digest(), 'binary'); const al = hash.readUInt32LE(0); const ah = hash.readUInt32LE(4); let i = 0; @@ -25,7 +25,12 @@ const getTable = function(key) { i = 1; while (i < 1024) { - table = merge_sort(table, (x, y) => ((((ah % (x + i)) * int32Max) + al) % (x + i)) - ((((ah % (y + i)) * int32Max) + al) % (y + i))); + table = merge_sort( + table, + (x, y) => + ((ah % (x + i)) * int32Max + al) % (x + i) - + ((ah % (y + i)) * int32Max + al) % (y + i) + ); i++; } i = 0; @@ -57,7 +62,7 @@ const EVP_BytesToKey = function(password, key_len, iv_len) { const m = []; let i = 0; let count = 0; - while (count < (key_len + iv_len)) { + while (count < key_len + iv_len) { const md5 = crypto.createHash('md5'); let data = password; if (i > 0) { @@ -76,7 +81,6 @@ const EVP_BytesToKey = function(password, key_len, iv_len) { return [key, iv]; }; - const method_supported = { 'aes-128-cfb': [16, 16], 'aes-192-cfb': [24, 16], @@ -89,12 +93,11 @@ const method_supported = { 'des-cfb': [8, 8], 'idea-cfb': [16, 8], 'rc2-cfb': [16, 8], - 'rc4': [16, 0], + rc4: [16, 0], 'rc4-md5': [16, 16], 'seed-cfb': [16, 16] }; - const create_rc4_md5_cipher = function(key, iv, op) { const md5 = crypto.createHash('md5'); md5.update(key); @@ -107,7 +110,6 @@ const create_rc4_md5_cipher = function(key, iv, op) { } }; - class Encryptor { constructor(key, method) { this.key = key; @@ -117,7 +119,12 @@ class Encryptor { this.method = null; } if (this.method) { - this.cipher = this.get_cipher(this.key, this.method, 1, crypto.randomBytes(32)); + this.cipher = this.get_cipher( + this.key, + this.method, + 1, + crypto.randomBytes(32) + ); } else { [this.encryptTable, this.decryptTable] = getTable(this.key); } diff --git a/local.js b/local.js index ad2ca905..ee3d98ce 100644 --- a/local.js +++ b/local.js @@ -1,31 +1,37 @@ -const net = require("net"); -const url = require("url"); -const http = require("http"); -const fs = require("fs"); -const path = require("path"); +const net = require('net'); +const url = require('url'); +const http = require('http'); +const fs = require('fs'); +const path = require('path'); const WebSocket = require('ws'); -const parseArgs = require("minimist"); +const parseArgs = require('minimist'); const HttpsProxyAgent = require('https-proxy-agent'); -const { Encryptor } = require("./encrypt"); +const { Encryptor } = require('./encrypt'); const options = { alias: { - 'b': 'local_address', - 'l': 'local_port', - 's': 'server', - 'r': 'remote_port', - 'k': 'password', - 'c': 'config_file', - 'm': 'method' + b: 'local_address', + l: 'local_port', + s: 'server', + r: 'remote_port', + k: 'password', + c: 'config_file', + m: 'method' }, - string: ['local_address', 'server', 'password', - 'config_file', 'method', 'scheme'], + string: [ + 'local_address', + 'server', + 'password', + 'config_file', + 'method', + 'scheme' + ], default: { - 'config_file': path.resolve(__dirname, "config.json") + config_file: path.resolve(__dirname, 'config.json') } }; -const inetNtoa = buf => buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3]; +const inetNtoa = buf => buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; const configFromArgs = parseArgs(process.argv.slice(2), options); const configContent = fs.readFileSync(configFromArgs.config_file); @@ -44,25 +50,29 @@ const KEY = config.password; let METHOD = config.method; const timeout = Math.floor(config.timeout * 1000); -if (["", "null", "table"].includes(METHOD.toLowerCase())) { +if (['', 'null', 'table'].includes(METHOD.toLowerCase())) { METHOD = null; } const HTTPPROXY = process.env.http_proxy; if (HTTPPROXY) { - console.log("http proxy:", HTTPPROXY); + console.log('http proxy:', HTTPPROXY); } const prepareServer = function(address) { const serverUrl = url.parse(address); serverUrl.slashes = true; - if (!serverUrl.protocol) { serverUrl.protocol = SCHEME; } + if (!serverUrl.protocol) { + serverUrl.protocol = SCHEME; + } if (!serverUrl.hostname) { serverUrl.hostname = address; serverUrl.pathname = '/'; } - if (!serverUrl.port) { serverUrl.port = REMOTE_PORT; } + if (!serverUrl.port) { + serverUrl.port = REMOTE_PORT; + } return url.format(serverUrl); }; @@ -81,9 +91,9 @@ const getServer = function() { }; var server = net.createServer(function(connection) { - console.log("local connected"); + console.log('local connected'); server.getConnections(function(err, count) { - console.log("concurrent connections:", count); + console.log('concurrent connections:', count); }); const encryptor = new Encryptor(KEY, METHOD); let stage = 0; @@ -94,21 +104,23 @@ var server = net.createServer(function(connection) { let ping = null; let remoteAddr = null; let remotePort = null; - let addrToSend = ""; + let addrToSend = ''; const aServer = getServer(); - connection.on("data", function(data) { + connection.on('data', function(data) { if (stage === 5) { // pipe sockets data = encryptor.encrypt(data); if (ws.readyState === WebSocket.OPEN) { ws.send(data, { binary: true }); - if (ws.bufferedAmount > 0) { connection.pause(); } + if (ws.bufferedAmount > 0) { + connection.pause(); + } } return; } if (stage === 0) { const tempBuf = new Buffer(2); - tempBuf.write("\u0005\u0000", 0); + tempBuf.write('\u0005\u0000', 0); connection.write(tempBuf); stage = 1; return; @@ -125,34 +137,34 @@ var server = net.createServer(function(connection) { const cmd = data[1]; const addrtype = data[3]; if (cmd !== 1) { - console.log("unsupported cmd:", cmd); - const reply = new Buffer("\u0005\u0007\u0000\u0001", "binary"); + console.log('unsupported cmd:', cmd); + const reply = new Buffer('\u0005\u0007\u0000\u0001', 'binary'); connection.end(reply); return; } if (addrtype === 3) { addrLen = data[4]; } else if (addrtype !== 1) { - console.log("unsupported addrtype:", addrtype); + console.log('unsupported addrtype:', addrtype); connection.end(); return; } - addrToSend = data.slice(3, 4).toString("binary"); + addrToSend = data.slice(3, 4).toString('binary'); // read address and port if (addrtype === 1) { remoteAddr = inetNtoa(data.slice(4, 8)); - addrToSend += data.slice(4, 10).toString("binary"); + addrToSend += data.slice(4, 10).toString('binary'); remotePort = data.readUInt16BE(8); headerLength = 10; } else { - remoteAddr = data.slice(5, 5 + addrLen).toString("binary"); - addrToSend += data.slice(4, 5 + addrLen + 2).toString("binary"); + remoteAddr = data.slice(5, 5 + addrLen).toString('binary'); + addrToSend += data.slice(4, 5 + addrLen + 2).toString('binary'); remotePort = data.readUInt16BE(5 + addrLen); headerLength = 5 + addrLen + 2; } let buf = new Buffer(10); - buf.write("\u0005\u0000\u0000\u0001", 0, 4, "binary"); - buf.write("\u0000\u0000\u0000\u0000", 4, 4, "binary"); + buf.write('\u0005\u0000\u0000\u0001', 0, 4, 'binary'); + buf.write('\u0000\u0000\u0000\u0000', 4, 4, 'binary'); buf.writeUInt16BE(remotePort, 8); connection.write(buf); // connect to remote server @@ -169,31 +181,33 @@ var server = net.createServer(function(connection) { // IMPORTANT! Set the `secureEndpoint` option to `false` when connecting // over "ws://", but `true` when connecting over "wss://" - opts.secureEndpoint = parsed.protocol ? parsed.protocol == 'wss:' : false + opts.secureEndpoint = parsed.protocol + ? parsed.protocol == 'wss:' + : false; const agent = new HttpsProxyAgent(opts); ws = new WebSocket(aServer, { - protocol: "binary", - agent - }); + protocol: 'binary', + agent + }); } else { ws = new WebSocket(aServer, { - protocol: "binary" - }); + protocol: 'binary' + }); } - ws.on("open", function() { - ws._socket.on("error", function(e) { + ws.on('open', function() { + ws._socket.on('error', function(e) { console.log(`remote ${remoteAddr}:${remotePort} ${e}`); connection.destroy(); server.getConnections(function(err, count) { - console.log("concurrent connections:", count); + console.log('concurrent connections:', count); }); }); console.log(`connecting ${remoteAddr} via ${aServer}`); - let addrToSendBuf = new Buffer(addrToSend, "binary"); + let addrToSendBuf = new Buffer(addrToSend, 'binary'); addrToSendBuf = encryptor.encrypt(addrToSendBuf); ws.send(addrToSendBuf, { binary: true }); let i = 0; @@ -207,29 +221,29 @@ var server = net.createServer(function(connection) { cachedPieces = null; // save memory stage = 5; - ping = setInterval(() => ws.ping("", null, true) - , 50 * 1000); - - ws._socket.on("drain", () => connection.resume()); + ping = setInterval(() => ws.ping('', null, true), 50 * 1000); + ws._socket.on('drain', () => connection.resume()); }); - ws.on("message", function(data, flags) { + ws.on('message', function(data, flags) { data = encryptor.decrypt(data); - if (!connection.write(data)) { ws._socket.pause(); } + if (!connection.write(data)) { + ws._socket.pause(); + } }); - ws.on("close", function() { + ws.on('close', function() { clearInterval(ping); - console.log("remote disconnected"); + console.log('remote disconnected'); connection.destroy(); }); - ws.on("error", function(e) { + ws.on('error', function(e) { console.log(`remote ${remoteAddr}:${remotePort} error: ${e}`); connection.destroy(); server.getConnections(function(err, count) { - console.log("concurrent connections:", count); + console.log('concurrent connections:', count); }); }); @@ -246,45 +260,57 @@ var server = net.createServer(function(connection) { console.log(e); connection.destroy(); } - } else if (stage === 4) { cachedPieces.push(data); } + } else if (stage === 4) { + cachedPieces.push(data); + } }); - // remote server not connected - // cache received buffers - // make sure no data is lost - - connection.on("end", function() { - console.log("local disconnected"); - if (ws) { ws.terminate(); } + // remote server not connected + // cache received buffers + // make sure no data is lost + + connection.on('end', function() { + console.log('local disconnected'); + if (ws) { + ws.terminate(); + } server.getConnections(function(err, count) { - console.log("concurrent connections:", count); + console.log('concurrent connections:', count); }); }); - connection.on("error", function(e){ + connection.on('error', function(e) { console.log(`local error: ${e}`); - if (ws) { ws.terminate(); } + if (ws) { + ws.terminate(); + } server.getConnections(function(err, count) { - console.log("concurrent connections:", count); + console.log('concurrent connections:', count); }); }); - connection.on("drain", function() { - if (ws && ws._socket) { ws._socket.resume(); } + connection.on('drain', function() { + if (ws && ws._socket) { + ws._socket.resume(); + } }); connection.setTimeout(timeout, function() { - console.log("local timeout"); + console.log('local timeout'); connection.destroy(); - if (ws) { ws.terminate(); } + if (ws) { + ws.terminate(); + } }); }); server.listen(PORT, LOCAL_ADDRESS, function() { const address = server.address(); - console.log("server listening at", address); + console.log('server listening at', address); }); -server.on("error", function(e) { - if (e.code === "EADDRINUSE") { console.log("address in use, aborting"); } +server.on('error', function(e) { + if (e.code === 'EADDRINUSE') { + console.log('address in use, aborting'); + } process.exit(1); }); diff --git a/merge_sort.js b/merge_sort.js index c0249c90..80ae7cf6 100644 --- a/merge_sort.js +++ b/merge_sort.js @@ -1,19 +1,29 @@ const merge = function(left, right, comparison) { const result = new Array(); - while ((left.length > 0) && (right.length > 0)) { + while (left.length > 0 && right.length > 0) { if (comparison(left[0], right[0]) <= 0) { result.push(left.shift()); } else { result.push(right.shift()); } } - while (left.length > 0) { result.push(left.shift()); } - while (right.length > 0) { result.push(right.shift()); } + while (left.length > 0) { + result.push(left.shift()); + } + while (right.length > 0) { + result.push(right.shift()); + } return result; }; var merge_sort = function(array, comparison) { - if (array.length < 2) { return array; } + if (array.length < 2) { + return array; + } const middle = Math.ceil(array.length / 2); - return merge(merge_sort(array.slice(0, middle), comparison), merge_sort(array.slice(middle), comparison), comparison); + return merge( + merge_sort(array.slice(0, middle), comparison), + merge_sort(array.slice(middle), comparison), + comparison + ); }; exports.merge_sort = merge_sort; diff --git a/server.js b/server.js index d6078c31..cb1694c2 100644 --- a/server.js +++ b/server.js @@ -1,36 +1,42 @@ -const net = require("net"); -const fs = require("fs"); -const path = require("path"); -const http = require("http"); +const net = require('net'); +const fs = require('fs'); +const path = require('path'); +const http = require('http'); const WebSocket = require('ws'); const WebSocketServer = WebSocket.Server; -const parseArgs = require("minimist"); -const { Encryptor } = require("./encrypt"); +const parseArgs = require('minimist'); +const { Encryptor } = require('./encrypt'); const options = { alias: { - 'b': 'local_address', - 'r': 'remote_port', - 'k': 'password', - 'c': 'config_file', - 'm': 'method' + b: 'local_address', + r: 'remote_port', + k: 'password', + c: 'config_file', + m: 'method' }, string: ['local_address', 'password', 'method', 'config_file'], default: { - 'config_file': path.resolve(__dirname, "config.json") + config_file: path.resolve(__dirname, 'config.json') } }; -const inetNtoa = buf => buf[0] + "." + buf[1] + "." + buf[2] + "." + buf[3]; +const inetNtoa = buf => buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; const configFromArgs = parseArgs(process.argv.slice(2), options); const configFile = configFromArgs.config_file; const configContent = fs.readFileSync(configFile); const config = JSON.parse(configContent); -if (process.env.PORT) { config['remote_port'] = +process.env.PORT; } -if (process.env.KEY) { config['password'] = process.env.KEY; } -if (process.env.METHOD) { config['method'] = process.env.METHOD; } +if (process.env.PORT) { + config['remote_port'] = +process.env.PORT; +} +if (process.env.KEY) { + config['password'] = process.env.KEY; +} +if (process.env.METHOD) { + config['method'] = process.env.METHOD; +} for (let k in configFromArgs) { const v = configFromArgs[k]; @@ -43,20 +49,20 @@ const PORT = config.remote_port; const KEY = config.password; let METHOD = config.method; -if (["", "null", "table"].includes(METHOD.toLowerCase())) { +if (['', 'null', 'table'].includes(METHOD.toLowerCase())) { METHOD = null; } const server = http.createServer(function(req, res) { - res.writeHead(200, {'Content-Type': 'text/plain'}); - res.end("asdf."); + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end('asdf.'); }); -const wss = new WebSocketServer({server}); +const wss = new WebSocketServer({ server }); -wss.on("connection", function(ws) { - console.log("server connected"); - console.log("concurrent connections:", wss.clients.length); +wss.on('connection', function(ws) { + console.log('server connected'); + console.log('concurrent connections:', wss.clients.length); const encryptor = new Encryptor(KEY, METHOD); let stage = 0; let headerLength = 0; @@ -65,10 +71,12 @@ wss.on("connection", function(ws) { let addrLen = 0; let remoteAddr = null; let remotePort = null; - ws.on("message", function(data, flags) { + ws.on('message', function(data, flags) { data = encryptor.decrypt(data); if (stage === 5) { - if (!remote.write(data)) { ws._socket.pause(); } + if (!remote.write(data)) { + ws._socket.pause(); + } } if (stage === 0) { try { @@ -86,14 +94,14 @@ wss.on("connection", function(ws) { remotePort = data.readUInt16BE(5); headerLength = 7; } else { - remoteAddr = data.slice(2, 2 + addrLen).toString("binary"); + remoteAddr = data.slice(2, 2 + addrLen).toString('binary'); remotePort = data.readUInt16BE(2 + addrLen); headerLength = 2 + addrLen + 2; } // connect remote server remote = net.connect(remotePort, remoteAddr, function() { - console.log("connecting", remoteAddr); + console.log('connecting', remoteAddr); let i = 0; while (i < cachedPieces.length) { @@ -104,28 +112,30 @@ wss.on("connection", function(ws) { cachedPieces = null; // save memory stage = 5; }); - remote.on("data", function(data) { + remote.on('data', function(data) { data = encryptor.encrypt(data); if (ws.readyState === WebSocket.OPEN) { ws.send(data, { binary: true }); - if (ws.bufferedAmount > 0) { remote.pause(); } + if (ws.bufferedAmount > 0) { + remote.pause(); + } } }); - remote.on("end", function() { + remote.on('end', function() { ws.close(); - console.log("remote disconnected"); + console.log('remote disconnected'); }); - remote.on("drain", () => ws._socket.resume()); + remote.on('drain', () => ws._socket.resume()); - remote.on("error", function(e){ + remote.on('error', function(e) { ws.terminate(); console.log(`remote: ${e}`); }); remote.setTimeout(timeout, function() { - console.log("remote timeout"); + console.log('remote timeout'); remote.destroy(); ws.close(); }); @@ -142,42 +152,52 @@ wss.on("connection", function(ws) { // may encouter index out of range const e = error; console.warn(e); - if (remote) { remote.destroy(); } + if (remote) { + remote.destroy(); + } ws.close(); } } else if (stage === 4) { - // remote server not connected - // cache received buffers - // make sure no data is lost - cachedPieces.push(data); + // remote server not connected + // cache received buffers + // make sure no data is lost + cachedPieces.push(data); } }); - ws.on("ping", () => ws.pong('', null, true)); + ws.on('ping', () => ws.pong('', null, true)); - ws._socket.on("drain", function() { - if (stage === 5) { remote.resume(); } + ws._socket.on('drain', function() { + if (stage === 5) { + remote.resume(); + } }); - ws.on("close", function() { - console.log("server disconnected"); - console.log("concurrent connections:", wss.clients.length); - if (remote) { remote.destroy(); } + ws.on('close', function() { + console.log('server disconnected'); + console.log('concurrent connections:', wss.clients.length); + if (remote) { + remote.destroy(); + } }); - ws.on("error", function(e) { + ws.on('error', function(e) { console.warn(`server: ${e}`); - console.log("concurrent connections:", wss.clients.length); - if (remote) { remote.destroy(); } + console.log('concurrent connections:', wss.clients.length); + if (remote) { + remote.destroy(); + } }); }); server.listen(PORT, LOCAL_ADDRESS, function() { const address = server.address(); - console.log("server listening at", address); + console.log('server listening at', address); }); -server.on("error", function(e) { - if (e.code === "EADDRINUSE") { console.log("address in use, aborting"); } +server.on('error', function(e) { + if (e.code === 'EADDRINUSE') { + console.log('address in use, aborting'); + } process.exit(1); }); diff --git a/test.js b/test.js index 305c2504..26ab846e 100644 --- a/test.js +++ b/test.js @@ -1,10 +1,10 @@ // test encryption -const encrypt = require("./encrypt"); +const encrypt = require('./encrypt'); const target = [ [ 60, 53, 84, 138, 217, 94, 88, 23, 39, 242, 219, 35, 12, 157, 165, 181, 255, 143, 83, 247, 162, 16, 31, 209, 190, 171, 115, 65, 38, 41, 21, 245, 236, 46, 121, 62, 166, 233, 44, 154, 153, 145, 230, 49, 128, 216, 173, 29, 241, 119, 64, 229, 194, 103, 131, 110, 26, 197, 218, 59, 204, 56, 27, 34, 141, 221, 149, 239, 192, 195, 24, 155, 170, 183, 11, 254, 213, 37, 137, 226, 75, 203, 55, 19, 72, 248, 22, 129, 33, 175, 178, 10, 198, 71, 77, 36, 113, 167, 48, 2, 117, 140, 142, 66, 199, 232, 243, 32, 123, 54, 51, 82, 57, 177, 87, 251, 150, 196, 133, 5, 253, 130, 8, 184, 14, 152, 231, 3, 186, 159, 76, 89, 228, 205, 156, 96, 163, 146, 18, 91, 132, 85, 80, 109, 172, 176, 105, 13, 50, 235, 127, 0, 189, 95, 98, 136, 250, 200, 108, 179, 211, 214, 106, 168, 78, 79, 74, 210, 30, 73, 201, 151, 208, 114, 101, 174, 92, 52, 120, 240, 15, 169, 220, 182, 81, 224, 43, 185, 40, 99, 180, 17, 212, 158, 42, 90, 9, 191, 45, 6, 25, 4, 222, 67, 126, 1, 116, 124, 206, 69, 61, 7, 68, 97, 202, 63, 244, 20, 28, 58, 93, 134, 104, 144, 227, 147, 102, 118, 135, 148, 47, 238, 86, 112, 122, 70, 107, 215, 100, 139, 223, 225, 164, 237, 111, 125, 207, 160, 187, 246, 234, 161, 188, 193, 249, 252 ], [ 151, 205, 99, 127, 201, 119, 199, 211, 122, 196, 91, 74, 12, 147, 124, 180, 21, 191, 138, 83, 217, 30, 86, 7, 70, 200, 56, 62, 218, 47, 168, 22, 107, 88, 63, 11, 95, 77, 28, 8, 188, 29, 194, 186, 38, 198, 33, 230, 98, 43, 148, 110, 177, 1, 109, 82, 61, 112, 219, 59, 0, 210, 35, 215, 50, 27, 103, 203, 212, 209, 235, 93, 84, 169, 166, 80, 130, 94, 164, 165, 142, 184, 111, 18, 2, 141, 232, 114, 6, 131, 195, 139, 176, 220, 5, 153, 135, 213, 154, 189, 238, 174, 226, 53, 222, 146, 162, 236, 158, 143, 55, 244, 233, 96, 173, 26, 206, 100, 227, 49, 178, 34, 234, 108, 207, 245, 204, 150, 44, 87, 121, 54, 140, 118, 221, 228, 155, 78, 3, 239, 101, 64, 102, 17, 223, 41, 137, 225, 229, 66, 116, 171, 125, 40, 39, 71, 134, 13, 193, 129, 247, 251, 20, 136, 242, 14, 36, 97, 163, 181, 72, 25, 144, 46, 175, 89, 145, 113, 90, 159, 190, 15, 183, 73, 123, 187, 128, 248, 252, 152, 24, 197, 68, 253, 52, 69, 117, 57, 92, 104, 157, 170, 214, 81, 60, 133, 208, 246, 172, 23, 167, 160, 192, 76, 161, 237, 45, 4, 58, 10, 182, 65, 202, 240, 185, 241, 79, 224, 132, 51, 42, 126, 105, 37, 250, 149, 32, 243, 231, 67, 179, 48, 9, 106, 216, 31, 249, 19, 85, 254, 156, 115, 255, 120, 75, 16 ] ]; -const tables = encrypt.getTable("foobar!"); +const tables = encrypt.getTable('foobar!'); console.log(JSON.stringify(tables)); let i = 0; @@ -22,14 +22,14 @@ const server = child_process.spawn('node', ['server.js']); let curlRunning = false; -local.on('exit', function(code){ +local.on('exit', function(code) { server.kill(); if (!curlRunning) { process.exit(code); } }); -server.on('exit', function(code){ +server.on('exit', function(code) { local.kill(); if (!curlRunning) { process.exit(code); @@ -42,8 +42,14 @@ curlRunning = false; const runCurl = function() { curlRunning = true; - const curl = child_process.spawn('curl', ['-v', 'http://www.example.com/', '-L', '--socks5-hostname', '127.0.0.1:1080']); - curl.on('exit', function(code){ + const curl = child_process.spawn('curl', [ + '-v', + 'http://www.example.com/', + '-L', + '--socks5-hostname', + '127.0.0.1:1080' + ]); + curl.on('exit', function(code) { local.kill(); server.kill(); if (code === 0) { From 590cc244ec699c56c8b9d4a913b78f520b0e7d61 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 4 Jan 2018 12:31:37 +0800 Subject: [PATCH 46/76] Upgrade dependencies --- package.json | 4 +-- test.js | 4 +-- yarn.lock | 69 ++++++++++++++++++++++++++++------------------------ 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/package.json b/package.json index b1250001..86a871e8 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,9 @@ "name": "shadowsocks-heroku", "version": "0.9.10", "dependencies": { - "https-proxy-agent": "^1.0.0", + "https-proxy-agent": "^2.1.1", "minimist": "^1.2.0", - "ws": "^1.0.1" + "ws": "^3.3.3" }, "scripts": { "start": "node server.js -b 0.0.0.0" diff --git a/test.js b/test.js index 26ab846e..1559232e 100644 --- a/test.js +++ b/test.js @@ -44,9 +44,9 @@ const runCurl = function() { curlRunning = true; const curl = child_process.spawn('curl', [ '-v', - 'http://www.example.com/', + 'https://www.example.com', '-L', - '--socks5-hostname', + '--socks5', '127.0.0.1:1080' ]); curl.on('exit', function(code) { diff --git a/yarn.lock b/yarn.lock index 86e5d674..fe7be537 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,30 +2,38 @@ # yarn lockfile v1 -agent-base@2: - version "2.1.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" +agent-base@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.1.2.tgz#80fa6cde440f4dcf9af2617cf246099b5d99f0c8" dependencies: - extend "~3.0.0" - semver "~5.0.1" + es6-promisify "^5.0.0" + +async-limiter@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" -debug@2: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" +debug@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: ms "2.0.0" -extend@3, extend@~3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" +es6-promise@^4.0.3: + version "4.2.2" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.2.tgz#f722d7769af88bd33bc13ec6605e1f92966b82d9" -https-proxy-agent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" dependencies: - agent-base "2" - debug "2" - extend "3" + es6-promise "^4.0.3" + +https-proxy-agent@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.1.1.tgz#a7ce4382a1ba8266ee848578778122d491260fd9" + dependencies: + agent-base "^4.1.0" + debug "^3.1.0" minimist@^1.2.0: version "1.2.0" @@ -35,21 +43,18 @@ ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" -options@>=0.0.5: - version "0.0.6" - resolved "https://registry.yarnpkg.com/options/-/options-0.0.6.tgz#ec22d312806bb53e731773e7cdaefcf1c643128f" - -semver@~5.0.1: - version "5.0.3" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.0.3.tgz#77466de589cd5d3c95f138aa78bc569a3cb5d27a" +safe-buffer@~5.1.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" -ultron@1.0.x: - version "1.0.2" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa" +ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" -ws@^1.0.1: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.5.tgz#cbd9e6e75e09fc5d2c90015f21f0c40875e0dd51" +ws@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" dependencies: - options ">=0.0.5" - ultron "1.0.x" + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" From 11265b6edaea7c86cdedaefce76d8e5524a4fa3b Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 4 Jan 2018 13:32:57 +0800 Subject: [PATCH 47/76] yarn add bufferutil --- package.json | 1 + yarn.lock | 300 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 300 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 86a871e8..18dc42b6 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "shadowsocks-heroku", "version": "0.9.10", "dependencies": { + "bufferutil": "^3.0.3", "https-proxy-agent": "^2.1.1", "minimist": "^1.2.0", "ws": "^3.3.3" diff --git a/yarn.lock b/yarn.lock index fe7be537..7084e8a4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8,16 +8,79 @@ agent-base@^4.1.0: dependencies: es6-promisify "^5.0.0" +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + +are-we-there-yet@~1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" +bindings@~1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7" + +bl@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e" + dependencies: + readable-stream "^2.0.5" + +bufferutil@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-3.0.3.tgz#ce67caefde2282591e399528467fe623f68f4bd5" + dependencies: + bindings "~1.3.0" + nan "~2.7.0" + prebuild-install "~2.3.0" + +chownr@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: ms "2.0.0" +deep-extend@~0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206" + dependencies: + once "^1.4.0" + es6-promise@^4.0.3: version "4.2.2" resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.2.tgz#f722d7769af88bd33bc13ec6605e1f92966b82d9" @@ -28,6 +91,31 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" +expand-template@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-1.1.0.tgz#e09efba977bf98f9ee0ed25abd0c692e02aec3fc" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + https-proxy-agent@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.1.1.tgz#a7ce4382a1ba8266ee848578778122d491260fd9" @@ -35,22 +123,228 @@ https-proxy-agent@^2.1.1: agent-base "^4.1.0" debug "^3.1.0" +inherits@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" +mkdirp@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" -safe-buffer@~5.1.0: +nan@~2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" + +node-abi@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.1.2.tgz#4da6caceb6685fcd31e7dd1994ef6bb7d0a9c0b2" + dependencies: + semver "^5.4.1" + +noop-logger@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" + +npmlog@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +prebuild-install@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-2.3.0.tgz#19481247df728b854ab57b187ce234211311b485" + dependencies: + expand-template "^1.0.2" + github-from-package "0.0.0" + minimist "^1.2.0" + mkdirp "^0.5.1" + node-abi "^2.1.1" + noop-logger "^0.1.1" + npmlog "^4.0.1" + os-homedir "^1.0.1" + pump "^1.0.1" + rc "^1.1.6" + simple-get "^1.4.2" + tar-fs "^1.13.0" + tunnel-agent "^0.6.0" + xtend "4.0.1" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +pump@^1.0.0, pump@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +rc@^1.1.6: + version "1.2.2" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6: + version "2.3.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" + util-deprecate "~1.0.1" + +safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" +semver@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +simple-get@^1.4.2: + version "1.4.3" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-1.4.3.tgz#e9755eda407e96da40c5e5158c9ea37b33becbeb" + dependencies: + once "^1.3.1" + unzip-response "^1.0.0" + xtend "^4.0.0" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +tar-fs@^1.13.0: + version "1.16.0" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.0.tgz#e877a25acbcc51d8c790da1c57c9cf439817b896" + dependencies: + chownr "^1.0.1" + mkdirp "^0.5.1" + pump "^1.0.0" + tar-stream "^1.1.2" + +tar-stream@^1.1.2: + version "1.5.5" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.5.tgz#5cad84779f45c83b1f2508d96b09d88c7218af55" + dependencies: + bl "^1.0.0" + end-of-stream "^1.0.0" + readable-stream "^2.0.0" + xtend "^4.0.0" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + ultron@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" +unzip-response@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +wide-align@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + dependencies: + string-width "^1.0.2" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + ws@^3.3.3: version "3.3.3" resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" @@ -58,3 +352,7 @@ ws@^3.3.3: async-limiter "~1.0.0" safe-buffer "~5.1.0" ultron "~1.1.0" + +xtend@4.0.1, xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" From 34ff097e6aede7c3090c29a906fa2c790743d552 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 4 Jan 2018 13:40:57 +0800 Subject: [PATCH 48/76] Fix concurrent connections --- local.js | 6 +++--- server.js | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/local.js b/local.js index ee3d98ce..2b589f0f 100644 --- a/local.js +++ b/local.js @@ -261,12 +261,12 @@ var server = net.createServer(function(connection) { connection.destroy(); } } else if (stage === 4) { + // remote server not connected + // cache received buffers + // make sure no data is lost cachedPieces.push(data); } }); - // remote server not connected - // cache received buffers - // make sure no data is lost connection.on('end', function() { console.log('local disconnected'); diff --git a/server.js b/server.js index cb1694c2..f8dd5bae 100644 --- a/server.js +++ b/server.js @@ -62,7 +62,7 @@ const wss = new WebSocketServer({ server }); wss.on('connection', function(ws) { console.log('server connected'); - console.log('concurrent connections:', wss.clients.length); + console.log('concurrent connections:', wss.clients.size); const encryptor = new Encryptor(KEY, METHOD); let stage = 0; let headerLength = 0; @@ -175,7 +175,7 @@ wss.on('connection', function(ws) { ws.on('close', function() { console.log('server disconnected'); - console.log('concurrent connections:', wss.clients.length); + console.log('concurrent connections:', wss.clients.size); if (remote) { remote.destroy(); } @@ -183,7 +183,7 @@ wss.on('connection', function(ws) { ws.on('error', function(e) { console.warn(`server: ${e}`); - console.log('concurrent connections:', wss.clients.length); + console.log('concurrent connections:', wss.clients.size); if (remote) { remote.destroy(); } From a004f0d34d45b771fa9f971b70c3b210c53f2424 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 4 Jan 2018 14:54:59 +0800 Subject: [PATCH 49/76] Do not touch ws._socket --- local.js | 10 +++++----- server.js | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/local.js b/local.js index 2b589f0f..933ba2bf 100644 --- a/local.js +++ b/local.js @@ -198,7 +198,7 @@ var server = net.createServer(function(connection) { } ws.on('open', function() { - ws._socket.on('error', function(e) { + ws.on('error', function(e) { console.log(`remote ${remoteAddr}:${remotePort} ${e}`); connection.destroy(); server.getConnections(function(err, count) { @@ -223,13 +223,13 @@ var server = net.createServer(function(connection) { ping = setInterval(() => ws.ping('', null, true), 50 * 1000); - ws._socket.on('drain', () => connection.resume()); + ws.on('drain', () => connection.resume()); }); ws.on('message', function(data, flags) { data = encryptor.decrypt(data); if (!connection.write(data)) { - ws._socket.pause(); + ws.pause(); } }); @@ -289,8 +289,8 @@ var server = net.createServer(function(connection) { }); connection.on('drain', function() { - if (ws && ws._socket) { - ws._socket.resume(); + if (ws) { + ws.resume(); } }); diff --git a/server.js b/server.js index f8dd5bae..5167fdf5 100644 --- a/server.js +++ b/server.js @@ -75,7 +75,7 @@ wss.on('connection', function(ws) { data = encryptor.decrypt(data); if (stage === 5) { if (!remote.write(data)) { - ws._socket.pause(); + ws.pause(); } } if (stage === 0) { @@ -127,7 +127,7 @@ wss.on('connection', function(ws) { console.log('remote disconnected'); }); - remote.on('drain', () => ws._socket.resume()); + remote.on('drain', () => ws.resume()); remote.on('error', function(e) { ws.terminate(); @@ -167,7 +167,7 @@ wss.on('connection', function(ws) { ws.on('ping', () => ws.pong('', null, true)); - ws._socket.on('drain', function() { + ws.on('drain', function() { if (stage === 5) { remote.resume(); } From 40ddb75273ffeef0a4e34d6f800d3beafc5544e9 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 4 Jan 2018 16:11:25 +0800 Subject: [PATCH 50/76] Delete redundant error handler. --- local.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/local.js b/local.js index 933ba2bf..b1466a67 100644 --- a/local.js +++ b/local.js @@ -198,14 +198,6 @@ var server = net.createServer(function(connection) { } ws.on('open', function() { - ws.on('error', function(e) { - console.log(`remote ${remoteAddr}:${remotePort} ${e}`); - connection.destroy(); - server.getConnections(function(err, count) { - console.log('concurrent connections:', count); - }); - }); - console.log(`connecting ${remoteAddr} via ${aServer}`); let addrToSendBuf = new Buffer(addrToSend, 'binary'); addrToSendBuf = encryptor.encrypt(addrToSendBuf); From 822994e2e0e3f6d70d26f2770c4267e8629548ec Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Thu, 4 Jan 2018 18:28:43 +0800 Subject: [PATCH 51/76] Remove buggy backpressure handling. --- local.js | 15 +-------------- server.js | 15 +-------------- 2 files changed, 2 insertions(+), 28 deletions(-) diff --git a/local.js b/local.js index b1466a67..d88b9c3a 100644 --- a/local.js +++ b/local.js @@ -112,9 +112,6 @@ var server = net.createServer(function(connection) { data = encryptor.encrypt(data); if (ws.readyState === WebSocket.OPEN) { ws.send(data, { binary: true }); - if (ws.bufferedAmount > 0) { - connection.pause(); - } } return; } @@ -214,15 +211,11 @@ var server = net.createServer(function(connection) { stage = 5; ping = setInterval(() => ws.ping('', null, true), 50 * 1000); - - ws.on('drain', () => connection.resume()); }); ws.on('message', function(data, flags) { data = encryptor.decrypt(data); - if (!connection.write(data)) { - ws.pause(); - } + connection.write(data); }); ws.on('close', function() { @@ -280,12 +273,6 @@ var server = net.createServer(function(connection) { }); }); - connection.on('drain', function() { - if (ws) { - ws.resume(); - } - }); - connection.setTimeout(timeout, function() { console.log('local timeout'); connection.destroy(); diff --git a/server.js b/server.js index 5167fdf5..cd5ecaaf 100644 --- a/server.js +++ b/server.js @@ -74,9 +74,7 @@ wss.on('connection', function(ws) { ws.on('message', function(data, flags) { data = encryptor.decrypt(data); if (stage === 5) { - if (!remote.write(data)) { - ws.pause(); - } + remote.write(data); } if (stage === 0) { try { @@ -116,9 +114,6 @@ wss.on('connection', function(ws) { data = encryptor.encrypt(data); if (ws.readyState === WebSocket.OPEN) { ws.send(data, { binary: true }); - if (ws.bufferedAmount > 0) { - remote.pause(); - } } }); @@ -127,8 +122,6 @@ wss.on('connection', function(ws) { console.log('remote disconnected'); }); - remote.on('drain', () => ws.resume()); - remote.on('error', function(e) { ws.terminate(); console.log(`remote: ${e}`); @@ -167,12 +160,6 @@ wss.on('connection', function(ws) { ws.on('ping', () => ws.pong('', null, true)); - ws.on('drain', function() { - if (stage === 5) { - remote.resume(); - } - }); - ws.on('close', function() { console.log('server disconnected'); console.log('concurrent connections:', wss.clients.size); From 005267827ca6f3517650c74bab6d7a20eea213ba Mon Sep 17 00:00:00 2001 From: HackingGate Date: Tue, 5 Mar 2019 22:38:21 +0900 Subject: [PATCH 52/76] yarn upgrade --latest --- package.json | 6 +- yarn.lock | 355 +++++---------------------------------------------- 2 files changed, 37 insertions(+), 324 deletions(-) diff --git a/package.json b/package.json index 18dc42b6..f9554f80 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,10 @@ "name": "shadowsocks-heroku", "version": "0.9.10", "dependencies": { - "bufferutil": "^3.0.3", - "https-proxy-agent": "^2.1.1", + "bufferutil": "^4.0.1", + "https-proxy-agent": "^2.2.1", "minimist": "^1.2.0", - "ws": "^3.3.3" + "ws": "^6.1.4" }, "scripts": { "start": "node server.js -b 0.0.0.0" diff --git a/yarn.lock b/yarn.lock index 7084e8a4..c76a3566 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,356 +3,69 @@ agent-base@^4.1.0: - version "4.1.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.1.2.tgz#80fa6cde440f4dcf9af2617cf246099b5d99f0c8" + version "4.2.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" + integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== dependencies: es6-promisify "^5.0.0" -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - -aproba@^1.0.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" - -are-we-there-yet@~1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.6" - async-limiter@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" + integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== -bindings@~1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7" - -bl@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e" - dependencies: - readable-stream "^2.0.5" - -bufferutil@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-3.0.3.tgz#ce67caefde2282591e399528467fe623f68f4bd5" +bufferutil@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.1.tgz#3a177e8e5819a1243fe16b63a199951a7ad8d4a7" + integrity sha512-xowrxvpxojqkagPcWRQVXZl0YXhRhAtBEIq3VoER1NH5Mw1n1o0ojdspp+GS2J//2gCVyrzQDApQ4unGF+QOoA== dependencies: - bindings "~1.3.0" - nan "~2.7.0" - prebuild-install "~2.3.0" - -chownr@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.0.1.tgz#e2a75042a9551908bebd25b8523d5f9769d79181" - -code-point-at@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - -core-util-is@~1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + node-gyp-build "~3.7.0" debug@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - dependencies: - ms "2.0.0" - -deep-extend@~0.4.0: - version "0.4.2" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" - -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - -end-of-stream@^1.0.0, end-of-stream@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206" + version "3.2.6" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" + integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== dependencies: - once "^1.4.0" + ms "^2.1.1" es6-promise@^4.0.3: - version "4.2.2" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.2.tgz#f722d7769af88bd33bc13ec6605e1f92966b82d9" + version "4.2.6" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f" + integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q== es6-promisify@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= dependencies: es6-promise "^4.0.3" -expand-template@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-1.1.0.tgz#e09efba977bf98f9ee0ed25abd0c692e02aec3fc" - -gauge@~2.7.3: - version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - wide-align "^1.1.0" - -github-from-package@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" - -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - -https-proxy-agent@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.1.1.tgz#a7ce4382a1ba8266ee848578778122d491260fd9" +https-proxy-agent@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" + integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== dependencies: agent-base "^4.1.0" debug "^3.1.0" -inherits@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - -ini@~1.3.0: - version "1.3.5" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" - -is-fullwidth-code-point@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" - dependencies: - number-is-nan "^1.0.0" - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= -mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - dependencies: - minimist "0.0.8" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - -nan@~2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46" - -node-abi@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.1.2.tgz#4da6caceb6685fcd31e7dd1994ef6bb7d0a9c0b2" - dependencies: - semver "^5.4.1" - -noop-logger@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" - -npmlog@^4.0.1: - version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.3" - set-blocking "~2.0.0" - -number-is-nan@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" - -object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - -once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - dependencies: - wrappy "1" - -os-homedir@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - -prebuild-install@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-2.3.0.tgz#19481247df728b854ab57b187ce234211311b485" - dependencies: - expand-template "^1.0.2" - github-from-package "0.0.0" - minimist "^1.2.0" - mkdirp "^0.5.1" - node-abi "^2.1.1" - noop-logger "^0.1.1" - npmlog "^4.0.1" - os-homedir "^1.0.1" - pump "^1.0.1" - rc "^1.1.6" - simple-get "^1.4.2" - tar-fs "^1.13.0" - tunnel-agent "^0.6.0" - xtend "4.0.1" - -process-nextick-args@~1.0.6: - version "1.0.7" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" - -pump@^1.0.0, pump@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -rc@^1.1.6: - version "1.2.2" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077" - dependencies: - deep-extend "~0.4.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~2.0.1" - -readable-stream@^2.0.0, readable-stream@^2.0.5, readable-stream@^2.0.6: - version "2.3.3" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - safe-buffer "~5.1.1" - string_decoder "~1.0.3" - util-deprecate "~1.0.1" - -safe-buffer@^5.0.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" - -semver@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" - -set-blocking@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - -signal-exit@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -simple-get@^1.4.2: - version "1.4.3" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-1.4.3.tgz#e9755eda407e96da40c5e5158c9ea37b33becbeb" - dependencies: - once "^1.3.1" - unzip-response "^1.0.0" - xtend "^4.0.0" - -string-width@^1.0.1, string-width@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - strip-ansi "^3.0.0" - -string_decoder@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" - dependencies: - safe-buffer "~5.1.0" - -strip-ansi@^3.0.0, strip-ansi@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - dependencies: - ansi-regex "^2.0.0" - -strip-json-comments@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" - -tar-fs@^1.13.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.0.tgz#e877a25acbcc51d8c790da1c57c9cf439817b896" - dependencies: - chownr "^1.0.1" - mkdirp "^0.5.1" - pump "^1.0.0" - tar-stream "^1.1.2" - -tar-stream@^1.1.2: - version "1.5.5" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.5.tgz#5cad84779f45c83b1f2508d96b09d88c7218af55" - dependencies: - bl "^1.0.0" - end-of-stream "^1.0.0" - readable-stream "^2.0.0" - xtend "^4.0.0" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - dependencies: - safe-buffer "^5.0.1" - -ultron@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - -unzip-response@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-1.0.2.tgz#b984f0877fc0a89c2c773cc1ef7b5b232b5b06fe" - -util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - -wide-align@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" - dependencies: - string-width "^1.0.2" +ms@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" + integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" +node-gyp-build@~3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d" + integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w== -ws@^3.3.3: - version "3.3.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" +ws@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" + integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA== dependencies: async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" - -xtend@4.0.1, xtend@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" From 22118e2e655cad207e2128cda785b399c5515641 Mon Sep 17 00:00:00 2001 From: fox Date: Tue, 5 Jul 2022 18:01:13 +0800 Subject: [PATCH 53/76] for audit fixed. --- yarn.lock | 102 +++++++++++++++++++++++++++--------------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/yarn.lock b/yarn.lock index c76a3566..e183b565 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,70 +2,70 @@ # yarn lockfile v1 -agent-base@^4.1.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" - integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== +"agent-base@^4.3.0": + "integrity" "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==" + "resolved" "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz" + "version" "4.3.0" dependencies: - es6-promisify "^5.0.0" + "es6-promisify" "^5.0.0" -async-limiter@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" - integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== +"async-limiter@~1.0.0": + "integrity" "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" + "resolved" "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz" + "version" "1.0.0" -bufferutil@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.1.tgz#3a177e8e5819a1243fe16b63a199951a7ad8d4a7" - integrity sha512-xowrxvpxojqkagPcWRQVXZl0YXhRhAtBEIq3VoER1NH5Mw1n1o0ojdspp+GS2J//2gCVyrzQDApQ4unGF+QOoA== +"bufferutil@^4.0.1": + "integrity" "sha512-xowrxvpxojqkagPcWRQVXZl0YXhRhAtBEIq3VoER1NH5Mw1n1o0ojdspp+GS2J//2gCVyrzQDApQ4unGF+QOoA==" + "resolved" "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.1.tgz" + "version" "4.0.1" dependencies: - node-gyp-build "~3.7.0" + "node-gyp-build" "~3.7.0" -debug@^3.1.0: - version "3.2.6" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" - integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== +"debug@^3.1.0": + "integrity" "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==" + "resolved" "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz" + "version" "3.2.6" dependencies: - ms "^2.1.1" + "ms" "^2.1.1" -es6-promise@^4.0.3: - version "4.2.6" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.6.tgz#b685edd8258886365ea62b57d30de28fadcd974f" - integrity sha512-aRVgGdnmW2OiySVPUC9e6m+plolMAJKjZnQlCwNSuK5yQ0JN61DZSO1X1Ufd1foqWRAlig0rhduTCHe7sVtK5Q== +"es6-promise@^4.0.3": + "integrity" "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + "resolved" "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz" + "version" "4.2.8" -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= +"es6-promisify@^5.0.0": + "integrity" "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==" + "resolved" "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz" + "version" "5.0.0" dependencies: - es6-promise "^4.0.3" + "es6-promise" "^4.0.3" -https-proxy-agent@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz#51552970fa04d723e04c56d04178c3f92592bbc0" - integrity sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ== +"https-proxy-agent@^2.2.1": + "integrity" "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==" + "resolved" "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz" + "version" "2.2.4" dependencies: - agent-base "^4.1.0" - debug "^3.1.0" + "agent-base" "^4.3.0" + "debug" "^3.1.0" -minimist@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= +"minimist@^1.2.0": + "integrity" "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "resolved" "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz" + "version" "1.2.6" -ms@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== +"ms@^2.1.1": + "integrity" "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz" + "version" "2.1.1" -node-gyp-build@~3.7.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-3.7.0.tgz#daa77a4f547b9aed3e2aac779eaf151afd60ec8d" - integrity sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w== +"node-gyp-build@~3.7.0": + "integrity" "sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w==" + "resolved" "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.7.0.tgz" + "version" "3.7.0" -ws@^6.1.4: - version "6.1.4" - resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.4.tgz#5b5c8800afab925e94ccb29d153c8d02c1776ef9" - integrity sha512-eqZfL+NE/YQc1/ZynhojeV8q+H050oR8AZ2uIev7RU10svA9ZnJUddHcOUZTJLinZ9yEfdA2kSATS2qZK5fhJA== +"ws@^6.1.4": + "integrity" "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==" + "resolved" "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz" + "version" "6.2.2" dependencies: - async-limiter "~1.0.0" + "async-limiter" "~1.0.0" From 881dd16a1688066fb98238303e74d078c479048b Mon Sep 17 00:00:00 2001 From: fox Date: Fri, 8 Jul 2022 10:56:21 +0800 Subject: [PATCH 54/76] more compatible --- local.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/local.js b/local.js index d88b9c3a..d9acea31 100644 --- a/local.js +++ b/local.js @@ -210,7 +210,7 @@ var server = net.createServer(function(connection) { cachedPieces = null; // save memory stage = 5; - ping = setInterval(() => ws.ping('', null, true), 50 * 1000); + ping = setInterval(() => ws.ping('', null, ()=>true), 50 * 1000); }); ws.on('message', function(data, flags) { From cc0dd70c36c4511dffe4149d5497d3f1b8bc2929 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 09:25:28 +0800 Subject: [PATCH 55/76] devenv init & bun --- .envrc | 3 + .gitignore | 11 ++++ bun.lockb | Bin 0 -> 4958 bytes config.json | 2 +- devenv.lock | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++ devenv.nix | 6 ++ devenv.yaml | 3 + test.js | 6 +- yarn.lock | 71 ------------------------ 9 files changed, 183 insertions(+), 75 deletions(-) create mode 100644 .envrc create mode 100755 bun.lockb create mode 100644 devenv.lock create mode 100644 devenv.nix create mode 100644 devenv.yaml delete mode 100644 yarn.lock diff --git a/.envrc b/.envrc new file mode 100644 index 00000000..6de8a8ac --- /dev/null +++ b/.envrc @@ -0,0 +1,3 @@ +source_url "https://raw.githubusercontent.com/cachix/devenv/d1f7b48e35e6dee421cfd0f51481d17f77586997/direnvrc" "sha256-YBzqskFZxmNb3kYVoKD9ZixoPXJh1C9ZvTLGFRkauZ0=" + +use devenv \ No newline at end of file diff --git a/.gitignore b/.gitignore index d1bed128..0fe3a028 100644 --- a/.gitignore +++ b/.gitignore @@ -59,3 +59,14 @@ typings/ # next.js build output .next + +# Devenv +.devenv* +devenv.local.nix + +# direnv +.direnv + +# pre-commit +.pre-commit-config.yaml + diff --git a/bun.lockb b/bun.lockb new file mode 100755 index 0000000000000000000000000000000000000000..852b0bfc3360431fb13d85e7ec0de766aac6d63a GIT binary patch literal 4958 zcmeHL3s6&M7QTT97}O97qvPT(mZIw}_vS&slp#0PdODo<5+ zbi;RwTfHq4Dn*6)4Rw>=&)FGOe#Pb zNyeoiEoBKe(_P(gA8t^E82#e;9cm^VP{H*{A2Rw>Ga z<9`b;5%%#>+l%I34ImspqJL3*JK&@2;|~;zr-5>Y9+Y=He@BhxgVq!IF*nl49&Fce zX03uWYKOD@RQ|X8J;EL|;D1?ogpJpcnqQwtm#x{-{xCl8HP<$-@!n@A_E%|xj&7@X zu#4{^o}MncSrdO%zvtDwL+YfD9*z9-oR?bGKZ;9JdF(s0q-OfRRzi%J7v&TS-+1xR z+$DZdGv@~s{$)75E|nD&uWC&dz3n#5z1ywU=X_CTTiFMK(G{GqTG*`!Vy^G`ezor; z-yn-6DCMU6=OI9Zc^&sYzd6V}rEb;cmZr1AbCXQt=2CGjW#3!Qx1awsYl`H?ws6-` zXZ?u1H;*3aD8I5bE~0IV>btrwcft0fg-Pbh4})!MY|8^$LoEETW&b!ZEN$-Thpty| zF6o^SdUC_q@bgz@zQK%M){uTMd-9DbGv^C`STN?8nv3+yQ;Blsnk9)GdpvaZuJ z>cpc}a+zCG=E|z5=(oLVm6gJthVu2Mg$}&v9>&7IKaV|AdRe8b{jB(tIRC)(sY~mR zCsy&=69XsI=6s!8E>R_k3%<>S&x;#6J8@3h~vHeE}bxTprz`nzapxaJ-K9 z8o#74eq{RLIWbp?1#g6|@ST>t;6}jlg+xN(*-sX&wS2tS{rH7WktnvQ@l;^cs(GR? zrY$BwHGN{o8ZYx--y46*=)jB56^fbfc`tKD^N3;70;PAWLw@bu^!L55UmR<8J^Y#* zFH&B=u6xMV)v*&N%Pune3uG0>ofmd{e^WDmSC05XR_oBBHMuzsyy$#l;rnf_s@^%j z^0v70)0A_%JVTSB^sRrsJni=5FIpGJzI!Zp_pH#*Q-xmI@x?i}D%#z--mXoX)`o~Y z_k1JVF#DA!y+DNXfX_SP=C?+qm1noCuKaSG#qSg^E4SlLwEV7Dd)9lC8+@T{us7=q64qfy-|MnK@-nsN3il>%81wx zCS~Pryu-i$Lw<*M%V_ilwf&Ol>9q;U7CPUz?0iGuhd&ZQxG7i`0kEGSKzkH@U!w0e zM2WsL(4I&8AKjbiPDb~f!p^4}059S}c*KeM5fA1@yoeLUyUWg31_cQcLHGh$=t7eM zCLQ`TW~uX}aUFx}4Hw=bIVGW_1c56eT)BWpM#+!|*G#y!0gn_s5`w_h6|RE76G}-b zIYHoh3)e+1ycJRy2Qaw8!j+IUf?(vqwHU6Mz!MB?;K9`yuA;yLk)hadordcv@PydL z!Ic}Xu&m=qs9=J?H5{(BtR8CwgwU4BC3fw+vshY}N*k%@bdEOamD*XHkZInuX`Ag4R-pw2fxQarF8!%xC)h-#%8j@*@N@cF7r`0=VEPPF4oC^Y z(rhSNFZd&aQD^iMrc*!QatVj~Qfxn-$I71;G=LU#LVav1aZ2kXz{u^fD B*@yrD literal 0 HcmV?d00001 diff --git a/config.json b/config.json index b67fa459..643fcbc4 100644 --- a/config.json +++ b/config.json @@ -6,5 +6,5 @@ "remote_port": 8080, "password": "`try*(^^$some^$%^complex>:<>?~password/", "timeout": 600, - "method": "rc4-md5" + "method": "aes-128-cfb" } diff --git a/devenv.lock b/devenv.lock new file mode 100644 index 00000000..2fde9653 --- /dev/null +++ b/devenv.lock @@ -0,0 +1,156 @@ +{ + "nodes": { + "devenv": { + "locked": { + "dir": "src/modules", + "lastModified": 1709300857, + "narHash": "sha256-jkK99RiSt5YfLWj3kAQoB8OB3idxLTdT9kfo/wILbjw=", + "owner": "cachix", + "repo": "devenv", + "rev": "f0319af4f966fb8bc25c6429f4f2e097e79116c2", + "type": "github" + }, + "original": { + "dir": "src/modules", + "owner": "cachix", + "repo": "devenv", + "type": "github" + } + }, + "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1701680307, + "narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "4022d587cbbfd70fe950c1e2083a02621806a725", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "gitignore": { + "inputs": { + "nixpkgs": [ + "pre-commit-hooks", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1703887061, + "narHash": "sha256-gGPa9qWNc6eCXT/+Z5/zMkyYOuRZqeFZBDbopNZQkuY=", + "owner": "hercules-ci", + "repo": "gitignore.nix", + "rev": "43e1aa1308018f37118e34d3a9cb4f5e75dc11d5", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "gitignore.nix", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1709386671, + "narHash": "sha256-VPqfBnIJ+cfa78pd4Y5Cr6sOWVW8GYHRVucxJGmRf8Q=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "fa9a51752f1b5de583ad5213eb621be071806663", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-stable": { + "locked": { + "lastModified": 1704874635, + "narHash": "sha256-YWuCrtsty5vVZvu+7BchAxmcYzTMfolSPP5io8+WYCg=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "3dc440faeee9e889fe2d1b4d25ad0f430d449356", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-23.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-compat": "flake-compat", + "flake-utils": "flake-utils", + "gitignore": "gitignore", + "nixpkgs": [ + "nixpkgs" + ], + "nixpkgs-stable": "nixpkgs-stable" + }, + "locked": { + "lastModified": 1708018599, + "narHash": "sha256-M+Ng6+SePmA8g06CmUZWi1AjG2tFBX9WCXElBHEKnyM=", + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "rev": "5df5a70ad7575f6601d91f0efec95dd9bc619431", + "type": "github" + }, + "original": { + "owner": "cachix", + "repo": "pre-commit-hooks.nix", + "type": "github" + } + }, + "root": { + "inputs": { + "devenv": "devenv", + "nixpkgs": "nixpkgs", + "pre-commit-hooks": "pre-commit-hooks" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/devenv.nix b/devenv.nix new file mode 100644 index 00000000..9e9a429f --- /dev/null +++ b/devenv.nix @@ -0,0 +1,6 @@ +{ pkgs, ... }: + +{ + languages.javascript.enable = true; + languages.javascript.package = pkgs.bun; +} diff --git a/devenv.yaml b/devenv.yaml new file mode 100644 index 00000000..c7cb5ced --- /dev/null +++ b/devenv.yaml @@ -0,0 +1,3 @@ +inputs: + nixpkgs: + url: github:NixOS/nixpkgs/nixpkgs-unstable diff --git a/test.js b/test.js index 1559232e..e9da225b 100644 --- a/test.js +++ b/test.js @@ -17,8 +17,8 @@ while (i < 256) { // test proxy const child_process = require('child_process'); -const local = child_process.spawn('node', ['local.js']); -const server = child_process.spawn('node', ['server.js']); +const local = child_process.spawn(process.execPath, ['local.js']); +const server = child_process.spawn(process.execPath, ['server.js']); let curlRunning = false; @@ -44,7 +44,7 @@ const runCurl = function() { curlRunning = true; const curl = child_process.spawn('curl', [ '-v', - 'https://www.example.com', + 'http://127.0.0.1:8080', '-L', '--socks5', '127.0.0.1:1080' diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index e183b565..00000000 --- a/yarn.lock +++ /dev/null @@ -1,71 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"agent-base@^4.3.0": - "integrity" "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==" - "resolved" "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz" - "version" "4.3.0" - dependencies: - "es6-promisify" "^5.0.0" - -"async-limiter@~1.0.0": - "integrity" "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" - "resolved" "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz" - "version" "1.0.0" - -"bufferutil@^4.0.1": - "integrity" "sha512-xowrxvpxojqkagPcWRQVXZl0YXhRhAtBEIq3VoER1NH5Mw1n1o0ojdspp+GS2J//2gCVyrzQDApQ4unGF+QOoA==" - "resolved" "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.1.tgz" - "version" "4.0.1" - dependencies: - "node-gyp-build" "~3.7.0" - -"debug@^3.1.0": - "integrity" "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==" - "resolved" "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz" - "version" "3.2.6" - dependencies: - "ms" "^2.1.1" - -"es6-promise@^4.0.3": - "integrity" "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" - "resolved" "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz" - "version" "4.2.8" - -"es6-promisify@^5.0.0": - "integrity" "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==" - "resolved" "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz" - "version" "5.0.0" - dependencies: - "es6-promise" "^4.0.3" - -"https-proxy-agent@^2.2.1": - "integrity" "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==" - "resolved" "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz" - "version" "2.2.4" - dependencies: - "agent-base" "^4.3.0" - "debug" "^3.1.0" - -"minimist@^1.2.0": - "integrity" "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" - "resolved" "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz" - "version" "1.2.6" - -"ms@^2.1.1": - "integrity" "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" - "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz" - "version" "2.1.1" - -"node-gyp-build@~3.7.0": - "integrity" "sha512-L/Eg02Epx6Si2NXmedx+Okg+4UHqmaf3TNcxd50SF9NQGcJaON3AtU++kax69XV7YWz4tUspqZSAsVofhFKG2w==" - "resolved" "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-3.7.0.tgz" - "version" "3.7.0" - -"ws@^6.1.4": - "integrity" "sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==" - "resolved" "https://registry.npmjs.org/ws/-/ws-6.2.2.tgz" - "version" "6.2.2" - dependencies: - "async-limiter" "~1.0.0" From fcefbea868d5d5a0ec06f9c975e568647155a86a Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 09:37:45 +0800 Subject: [PATCH 56/76] Update dependencies. --- bun.lockb | Bin 4958 -> 3974 bytes local.js | 2 +- package.json | 4 ++-- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bun.lockb b/bun.lockb index 852b0bfc3360431fb13d85e7ec0de766aac6d63a..06eb9f286957d44ba1b489719d2f06179ace5e42 100755 GIT binary patch delta 1353 zcmcbo)+RqePxHU#rSMH{hn8ghU4Frbt8Yhr<;9H;Rz(ZWKlkpPNZ;EH-}o57fOBHF zym~4pgaaXk7#JGLi{WerE+Bsikjpo5s5F=#10cCW6GE6{GAd`U! zriVufC}aaQ4d@aBO^{{~1}S9&Vvur}Rme2c_4MXSG-Ef=JM60#t5;xX%UD)4 znU`In-d40#?#Yz958gUVen01$wdzT^?GazLPhMwru-N9$n<|H&H)qzYbU&)_QE4;l zE2WRuBm>Vi*6)`7eaPfSTsu$vM4)3B8UFGA1BM|i=s@mc*^tS9{Ase$&4w38zrAa) z5D|3I37DDQvLkMJn`OcJ*QbMjnSI~qe^K(}qG|Tdm$g;b&e+m(asRARmm_<3o7%Xw z-=4geUBY4UpT~w%64fO?y?N6j{&?lb`gwJV+}t~@PrNvDj{S4k;>~d@87C%Lf9(=3 zd7ZN}y^=M3#bwfuF3m&jHEy*1mrc46iCJbm?IgdA-)m+a&&t&o`UVU2&Jwr1+0|sDz17|5%77}5MGXbhG zWMGH_$^i3e!v#~3kjOh<*hLuaY)yeuMhr_BCeP!OsE6go)W55(WG(BzGBL)1j0fhG zl+>isbfEUWW(JdoQm2kFF`58*Adm~q+Do<^xw`dwzXubek)9z)3l=>z4q0lmXUWXz6uAQA3j_IYS91sz=05%X9LVPd@}CEtI-Yf#vwQ;7&Uerf zi_50e!cM_Zp*XWDH9t*fay@^d1SBN&O46%JOVV^LbjuQRGE)*uQYRM(NKY0N+B#WD vPqleQQA6ND)(*LYD0;2sa2<_sBKq^ecs`#?7#b*^Ud=;x8L)8&w1b9?6PXLKO~xB zejuv6;V-wgp_Unyg8UN=bu;&;W%_8(`TAKf!`Y;s)|k+VK}L|3Rfxf`G5iaWltlIL z`*Kjcj9gpqFGzymKtKzc2YLdHAh@704EE=NZ3ucsv8rV7-OU&l!*6T(0gw8gyQvAn zqnG3}KEiQG@ua6N&stbqu`2|YbhCLOhPH#y>Mx;N_0YLNs6z~Wd z5|ES70#cu+0BaURpgTbz8~Rl2rJW;?In7hh2EH#Ls4IbY2301ILcRndbnxOR>qA5V z5!?!UF({pi@D79N0TITCSJ#T&3|>3{6Y|8kIeRjcdg44}Lvy7mXegWXr1jF!LsEvU zNrpSF#}7tl!h_{gt(ymYIIfR_AXt-VE8W5ucKbp87ZOv4gj(p)-r7j{g`F9_-61*C z>78+nT@Ol5R&8+j{z%1(ECx+HKS|J96LKdi+db!uV%^mq^B;r8wCwF!oEV{>dnv4D z{+}AOpJC=7d*jTqFiW4nVB7qk$I163s5wR3+Y-QAdXE%9KV`B z;O3ybm;Lt+)0w6Yd3g>ot*pl`_zQ_a{vdod9r-bX&^#tjGj09vrwkL9m3Pzcw1y2W zl$Gt9++5qMWt)9lA{HI_WI7feYeX2u`61>> zXM_B17jfpuwwVS*uefhpxRO|%|I@9|-Fd$pXBA%W7YO{vH#J_g^Vz;!FiqL%XB#o! z>+MdXl;6H_y%>vf^~^NfuH=QyW`+TFPJdLpd}iGA=(zWdNh$QR)Ah(%Qth4rgTp)g zy=F^pC{Lc2RK#XpKW6;8CO9iie0@thuV80-8caj&j!lgQnqhgUsyZ{cvO`??Ys?i@ z&c-IU(yv}k4Cv^4*1pPr*ZK5gi)4=z_(pacT#M4$DtcLQL+=kB-0dRZX20g|Tl)E% zp-+H0=oll2}HASiHDHg=w(6Hcn@cC^U zNipD|Dz?NP2uF97Fi+sifv*kTES}#D*a=GnPMs*jsW=5Q0KRF|t;5Fzm*Y}ghPz~q zlwL4IQJf&AL?jV8p*oIukxb+yk`jcD4B^I8oJJ$JIf)!ajs!umqkN!X+5~saTN)WE z6*=QbgnV`UTEIS#N=Vzy>#88)3}}uhg=-QP3JpX~1VNE1MUar>G7L=7EJc|*U`LTN zK~RKCk>|&j1Rwf=gz?ceuD9mDiK~@SqIE#;Q;Q!q+c%O&e}I*YgRjbKEHf&;XSuB! zY}iIhM)Rd?%bawRyI_w2ySqT&I7ap4{S&b9KR{PtUG=(VcH*Itc2)Qmf^aC>~`C@p_$5p`jJ( zh?XlP7YO8AG746YUDyGOyQ=RZ49pr&17Z$3o*nvjQ{`u diff --git a/local.js b/local.js index d9acea31..2b006b24 100644 --- a/local.js +++ b/local.js @@ -5,7 +5,7 @@ const fs = require('fs'); const path = require('path'); const WebSocket = require('ws'); const parseArgs = require('minimist'); -const HttpsProxyAgent = require('https-proxy-agent'); +const { HttpsProxyAgent } = require('https-proxy-agent'); const { Encryptor } = require('./encrypt'); const options = { diff --git a/package.json b/package.json index f9554f80..d3837738 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,9 @@ "version": "0.9.10", "dependencies": { "bufferutil": "^4.0.1", - "https-proxy-agent": "^2.2.1", + "https-proxy-agent": "^7.0.4", "minimist": "^1.2.0", - "ws": "^6.1.4" + "ws": "^8.16.0" }, "scripts": { "start": "node server.js -b 0.0.0.0" From ba2fa5cd1f73c61d24e0e292d8c0f8461cddd9a7 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 09:45:59 +0800 Subject: [PATCH 57/76] merge_sort.js -> Array.sort --- encrypt.js | 10 +++------- merge_sort.js | 29 ----------------------------- 2 files changed, 3 insertions(+), 36 deletions(-) delete mode 100644 merge_sort.js diff --git a/encrypt.js b/encrypt.js index 183c5ab5..d1d04ef1 100644 --- a/encrypt.js +++ b/encrypt.js @@ -1,5 +1,4 @@ const crypto = require('crypto'); -const { merge_sort } = require('./merge_sort'); const int32Max = Math.pow(2, 32); const cachedTables = {}; // password: [encryptTable, decryptTable] @@ -25,12 +24,9 @@ const getTable = function(key) { i = 1; while (i < 1024) { - table = merge_sort( - table, - (x, y) => - ((ah % (x + i)) * int32Max + al) % (x + i) - - ((ah % (y + i)) * int32Max + al) % (y + i) - ); + table.sort((x, y) => + ((ah % (x + i)) * int32Max + al) % (x + i) - + ((ah % (y + i)) * int32Max + al) % (y + i)); i++; } i = 0; diff --git a/merge_sort.js b/merge_sort.js deleted file mode 100644 index 80ae7cf6..00000000 --- a/merge_sort.js +++ /dev/null @@ -1,29 +0,0 @@ -const merge = function(left, right, comparison) { - const result = new Array(); - while (left.length > 0 && right.length > 0) { - if (comparison(left[0], right[0]) <= 0) { - result.push(left.shift()); - } else { - result.push(right.shift()); - } - } - while (left.length > 0) { - result.push(left.shift()); - } - while (right.length > 0) { - result.push(right.shift()); - } - return result; -}; -var merge_sort = function(array, comparison) { - if (array.length < 2) { - return array; - } - const middle = Math.ceil(array.length / 2); - return merge( - merge_sort(array.slice(0, middle), comparison), - merge_sort(array.slice(middle), comparison), - comparison - ); -}; -exports.merge_sort = merge_sort; From 0d758d85cec2b2f15ef05aae613694abdf46f630 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 09:51:19 +0800 Subject: [PATCH 58/76] prettier --- .prettierrc | 4 ++++ bun.lockb | Bin 3974 -> 4334 bytes config.json | 20 ++++++++--------- encrypt.js | 20 +++++++++-------- local.js | 62 +++++++++++++++++++++++++-------------------------- package.json | 6 ++++- server.js | 40 ++++++++++++++++----------------- test.js | 60 ++++++++++++++++++++++++++++++++++++++----------- 8 files changed, 128 insertions(+), 84 deletions(-) create mode 100644 .prettierrc diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..f8011d0b --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "bracketSpacing": false, + "singleQuote": true +} \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 06eb9f286957d44ba1b489719d2f06179ace5e42..40eb076f113a67c857f944764f740c1446b2101c 100755 GIT binary patch delta 626 zcmZpZf2TM>PxG-z-qwrDw>_9=#%rtlK7NhTk5`Yka6c~UO?>_1Q~LMfH~|JQ;F=gN z&y>V9u_Az@peVJZBr~;W;t3CqJ8=d{+f9yt)0MiynBkZg(u= znvpQ~sl19!YwW$%DGKU4Hsrr_ZwT0(-D-dI0nq36lTFwwfZ@U-01LG^pcjE*+5nU^ z*nEe*lW`J@A=e6!pMhWx*W?4-B9ogrHD!UkfBzu>Bm;8T3#cj{?#ahEjpSH>LZGk& zg&#;7Bx?Z;v<#3EB}UH4rd$S`P_YXRLL}3nrMI8qy%r{TwQfA~*-~}>)pn(_Y z3EuVDk!&PDZX3AX|Z859j0@E?cR8{~-V*!~w)F zpwb*%laFy3NrAioayCc`Bx3<}YYIqOZL$rwE+:<>?~password/", - "timeout": 600, - "method": "aes-128-cfb" -} +{ + "server": "127.0.0.1", + "local_address": "127.0.0.1", + "scheme": "ws", + "local_port": 1080, + "remote_port": 8080, + "password": "`try*(^^$some^$%^complex>:<>?~password/", + "timeout": 600, + "method": "aes-128-cfb" +} diff --git a/encrypt.js b/encrypt.js index d1d04ef1..4b9d3787 100644 --- a/encrypt.js +++ b/encrypt.js @@ -3,7 +3,7 @@ const int32Max = Math.pow(2, 32); const cachedTables = {}; // password: [encryptTable, decryptTable] -const getTable = function(key) { +const getTable = function (key) { if (cachedTables[key]) { return cachedTables[key]; } @@ -24,9 +24,11 @@ const getTable = function(key) { i = 1; while (i < 1024) { - table.sort((x, y) => - ((ah % (x + i)) * int32Max + al) % (x + i) - - ((ah % (y + i)) * int32Max + al) % (y + i)); + table.sort( + (x, y) => + (((ah % (x + i)) * int32Max + al) % (x + i)) - + (((ah % (y + i)) * int32Max + al) % (y + i)), + ); i++; } i = 0; @@ -39,7 +41,7 @@ const getTable = function(key) { return result; }; -const substitute = function(table, buf) { +const substitute = function (table, buf) { let i = 0; while (i < buf.length) { @@ -51,7 +53,7 @@ const substitute = function(table, buf) { const bytes_to_key_results = {}; -const EVP_BytesToKey = function(password, key_len, iv_len) { +const EVP_BytesToKey = function (password, key_len, iv_len) { if (bytes_to_key_results[`${password}:${key_len}:${iv_len}`]) { return bytes_to_key_results[`${password}:${key_len}:${iv_len}`]; } @@ -91,10 +93,10 @@ const method_supported = { 'rc2-cfb': [16, 8], rc4: [16, 0], 'rc4-md5': [16, 16], - 'seed-cfb': [16, 16] + 'seed-cfb': [16, 16], }; -const create_rc4_md5_cipher = function(key, iv, op) { +const create_rc4_md5_cipher = function (key, iv, op) { const md5 = crypto.createHash('md5'); md5.update(key); md5.update(iv); @@ -119,7 +121,7 @@ class Encryptor { this.key, this.method, 1, - crypto.randomBytes(32) + crypto.randomBytes(32), ); } else { [this.encryptTable, this.decryptTable] = getTable(this.key); diff --git a/local.js b/local.js index 2b006b24..e1924067 100644 --- a/local.js +++ b/local.js @@ -5,8 +5,8 @@ const fs = require('fs'); const path = require('path'); const WebSocket = require('ws'); const parseArgs = require('minimist'); -const { HttpsProxyAgent } = require('https-proxy-agent'); -const { Encryptor } = require('./encrypt'); +const {HttpsProxyAgent} = require('https-proxy-agent'); +const {Encryptor} = require('./encrypt'); const options = { alias: { @@ -16,7 +16,7 @@ const options = { r: 'remote_port', k: 'password', c: 'config_file', - m: 'method' + m: 'method', }, string: [ 'local_address', @@ -24,14 +24,14 @@ const options = { 'password', 'config_file', 'method', - 'scheme' + 'scheme', ], default: { - config_file: path.resolve(__dirname, 'config.json') - } + config_file: path.resolve(__dirname, 'config.json'), + }, }; -const inetNtoa = buf => buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; +const inetNtoa = (buf) => buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; const configFromArgs = parseArgs(process.argv.slice(2), options); const configContent = fs.readFileSync(configFromArgs.config_file); @@ -60,7 +60,7 @@ if (HTTPPROXY) { console.log('http proxy:', HTTPPROXY); } -const prepareServer = function(address) { +const prepareServer = function (address) { const serverUrl = url.parse(address); serverUrl.slashes = true; if (!serverUrl.protocol) { @@ -77,12 +77,12 @@ const prepareServer = function(address) { }; if (SERVER instanceof Array) { - SERVER = SERVER.map(s => prepareServer(s)); + SERVER = SERVER.map((s) => prepareServer(s)); } else { SERVER = prepareServer(SERVER); } -const getServer = function() { +const getServer = function () { if (SERVER instanceof Array) { return SERVER[Math.floor(Math.random() * SERVER.length)]; } else { @@ -90,9 +90,9 @@ const getServer = function() { } }; -var server = net.createServer(function(connection) { +var server = net.createServer(function (connection) { console.log('local connected'); - server.getConnections(function(err, count) { + server.getConnections(function (err, count) { console.log('concurrent connections:', count); }); const encryptor = new Encryptor(KEY, METHOD); @@ -106,12 +106,12 @@ var server = net.createServer(function(connection) { let remotePort = null; let addrToSend = ''; const aServer = getServer(); - connection.on('data', function(data) { + connection.on('data', function (data) { if (stage === 5) { // pipe sockets data = encryptor.encrypt(data); if (ws.readyState === WebSocket.OPEN) { - ws.send(data, { binary: true }); + ws.send(data, {binary: true}); } return; } @@ -186,48 +186,48 @@ var server = net.createServer(function(connection) { ws = new WebSocket(aServer, { protocol: 'binary', - agent + agent, }); } else { ws = new WebSocket(aServer, { - protocol: 'binary' + protocol: 'binary', }); } - ws.on('open', function() { + ws.on('open', function () { console.log(`connecting ${remoteAddr} via ${aServer}`); let addrToSendBuf = new Buffer(addrToSend, 'binary'); addrToSendBuf = encryptor.encrypt(addrToSendBuf); - ws.send(addrToSendBuf, { binary: true }); + ws.send(addrToSendBuf, {binary: true}); let i = 0; while (i < cachedPieces.length) { let piece = cachedPieces[i]; piece = encryptor.encrypt(piece); - ws.send(piece, { binary: true }); + ws.send(piece, {binary: true}); i++; } cachedPieces = null; // save memory stage = 5; - ping = setInterval(() => ws.ping('', null, ()=>true), 50 * 1000); + ping = setInterval(() => ws.ping('', null, () => true), 50 * 1000); }); - ws.on('message', function(data, flags) { + ws.on('message', function (data, flags) { data = encryptor.decrypt(data); connection.write(data); }); - ws.on('close', function() { + ws.on('close', function () { clearInterval(ping); console.log('remote disconnected'); connection.destroy(); }); - ws.on('error', function(e) { + ws.on('error', function (e) { console.log(`remote ${remoteAddr}:${remotePort} error: ${e}`); connection.destroy(); - server.getConnections(function(err, count) { + server.getConnections(function (err, count) { console.log('concurrent connections:', count); }); }); @@ -253,27 +253,27 @@ var server = net.createServer(function(connection) { } }); - connection.on('end', function() { + connection.on('end', function () { console.log('local disconnected'); if (ws) { ws.terminate(); } - server.getConnections(function(err, count) { + server.getConnections(function (err, count) { console.log('concurrent connections:', count); }); }); - connection.on('error', function(e) { + connection.on('error', function (e) { console.log(`local error: ${e}`); if (ws) { ws.terminate(); } - server.getConnections(function(err, count) { + server.getConnections(function (err, count) { console.log('concurrent connections:', count); }); }); - connection.setTimeout(timeout, function() { + connection.setTimeout(timeout, function () { console.log('local timeout'); connection.destroy(); if (ws) { @@ -282,12 +282,12 @@ var server = net.createServer(function(connection) { }); }); -server.listen(PORT, LOCAL_ADDRESS, function() { +server.listen(PORT, LOCAL_ADDRESS, function () { const address = server.address(); console.log('server listening at', address); }); -server.on('error', function(e) { +server.on('error', function (e) { if (e.code === 'EADDRINUSE') { console.log('address in use, aborting'); } diff --git a/package.json b/package.json index d3837738..4d198f77 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,10 @@ "ws": "^8.16.0" }, "scripts": { - "start": "node server.js -b 0.0.0.0" + "start": "node server.js -b 0.0.0.0", + "format": "prettier --write '*.{js,json}'" + }, + "devDependencies": { + "prettier": "^3.2.5" } } diff --git a/server.js b/server.js index cd5ecaaf..a830aab9 100644 --- a/server.js +++ b/server.js @@ -5,7 +5,7 @@ const http = require('http'); const WebSocket = require('ws'); const WebSocketServer = WebSocket.Server; const parseArgs = require('minimist'); -const { Encryptor } = require('./encrypt'); +const {Encryptor} = require('./encrypt'); const options = { alias: { @@ -13,15 +13,15 @@ const options = { r: 'remote_port', k: 'password', c: 'config_file', - m: 'method' + m: 'method', }, string: ['local_address', 'password', 'method', 'config_file'], default: { - config_file: path.resolve(__dirname, 'config.json') - } + config_file: path.resolve(__dirname, 'config.json'), + }, }; -const inetNtoa = buf => buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; +const inetNtoa = (buf) => buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; const configFromArgs = parseArgs(process.argv.slice(2), options); const configFile = configFromArgs.config_file; @@ -53,14 +53,14 @@ if (['', 'null', 'table'].includes(METHOD.toLowerCase())) { METHOD = null; } -const server = http.createServer(function(req, res) { - res.writeHead(200, { 'Content-Type': 'text/plain' }); +const server = http.createServer(function (req, res) { + res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('asdf.'); }); -const wss = new WebSocketServer({ server }); +const wss = new WebSocketServer({server}); -wss.on('connection', function(ws) { +wss.on('connection', function (ws) { console.log('server connected'); console.log('concurrent connections:', wss.clients.size); const encryptor = new Encryptor(KEY, METHOD); @@ -71,7 +71,7 @@ wss.on('connection', function(ws) { let addrLen = 0; let remoteAddr = null; let remotePort = null; - ws.on('message', function(data, flags) { + ws.on('message', function (data, flags) { data = encryptor.decrypt(data); if (stage === 5) { remote.write(data); @@ -98,7 +98,7 @@ wss.on('connection', function(ws) { } // connect remote server - remote = net.connect(remotePort, remoteAddr, function() { + remote = net.connect(remotePort, remoteAddr, function () { console.log('connecting', remoteAddr); let i = 0; @@ -110,24 +110,24 @@ wss.on('connection', function(ws) { cachedPieces = null; // save memory stage = 5; }); - remote.on('data', function(data) { + remote.on('data', function (data) { data = encryptor.encrypt(data); if (ws.readyState === WebSocket.OPEN) { - ws.send(data, { binary: true }); + ws.send(data, {binary: true}); } }); - remote.on('end', function() { + remote.on('end', function () { ws.close(); console.log('remote disconnected'); }); - remote.on('error', function(e) { + remote.on('error', function (e) { ws.terminate(); console.log(`remote: ${e}`); }); - remote.setTimeout(timeout, function() { + remote.setTimeout(timeout, function () { console.log('remote timeout'); remote.destroy(); ws.close(); @@ -160,7 +160,7 @@ wss.on('connection', function(ws) { ws.on('ping', () => ws.pong('', null, true)); - ws.on('close', function() { + ws.on('close', function () { console.log('server disconnected'); console.log('concurrent connections:', wss.clients.size); if (remote) { @@ -168,7 +168,7 @@ wss.on('connection', function(ws) { } }); - ws.on('error', function(e) { + ws.on('error', function (e) { console.warn(`server: ${e}`); console.log('concurrent connections:', wss.clients.size); if (remote) { @@ -177,12 +177,12 @@ wss.on('connection', function(ws) { }); }); -server.listen(PORT, LOCAL_ADDRESS, function() { +server.listen(PORT, LOCAL_ADDRESS, function () { const address = server.address(); console.log('server listening at', address); }); -server.on('error', function(e) { +server.on('error', function (e) { if (e.code === 'EADDRINUSE') { console.log('address in use, aborting'); } diff --git a/test.js b/test.js index e9da225b..d53b4665 100644 --- a/test.js +++ b/test.js @@ -1,8 +1,42 @@ // test encryption const encrypt = require('./encrypt'); const target = [ - [ 60, 53, 84, 138, 217, 94, 88, 23, 39, 242, 219, 35, 12, 157, 165, 181, 255, 143, 83, 247, 162, 16, 31, 209, 190, 171, 115, 65, 38, 41, 21, 245, 236, 46, 121, 62, 166, 233, 44, 154, 153, 145, 230, 49, 128, 216, 173, 29, 241, 119, 64, 229, 194, 103, 131, 110, 26, 197, 218, 59, 204, 56, 27, 34, 141, 221, 149, 239, 192, 195, 24, 155, 170, 183, 11, 254, 213, 37, 137, 226, 75, 203, 55, 19, 72, 248, 22, 129, 33, 175, 178, 10, 198, 71, 77, 36, 113, 167, 48, 2, 117, 140, 142, 66, 199, 232, 243, 32, 123, 54, 51, 82, 57, 177, 87, 251, 150, 196, 133, 5, 253, 130, 8, 184, 14, 152, 231, 3, 186, 159, 76, 89, 228, 205, 156, 96, 163, 146, 18, 91, 132, 85, 80, 109, 172, 176, 105, 13, 50, 235, 127, 0, 189, 95, 98, 136, 250, 200, 108, 179, 211, 214, 106, 168, 78, 79, 74, 210, 30, 73, 201, 151, 208, 114, 101, 174, 92, 52, 120, 240, 15, 169, 220, 182, 81, 224, 43, 185, 40, 99, 180, 17, 212, 158, 42, 90, 9, 191, 45, 6, 25, 4, 222, 67, 126, 1, 116, 124, 206, 69, 61, 7, 68, 97, 202, 63, 244, 20, 28, 58, 93, 134, 104, 144, 227, 147, 102, 118, 135, 148, 47, 238, 86, 112, 122, 70, 107, 215, 100, 139, 223, 225, 164, 237, 111, 125, 207, 160, 187, 246, 234, 161, 188, 193, 249, 252 ], - [ 151, 205, 99, 127, 201, 119, 199, 211, 122, 196, 91, 74, 12, 147, 124, 180, 21, 191, 138, 83, 217, 30, 86, 7, 70, 200, 56, 62, 218, 47, 168, 22, 107, 88, 63, 11, 95, 77, 28, 8, 188, 29, 194, 186, 38, 198, 33, 230, 98, 43, 148, 110, 177, 1, 109, 82, 61, 112, 219, 59, 0, 210, 35, 215, 50, 27, 103, 203, 212, 209, 235, 93, 84, 169, 166, 80, 130, 94, 164, 165, 142, 184, 111, 18, 2, 141, 232, 114, 6, 131, 195, 139, 176, 220, 5, 153, 135, 213, 154, 189, 238, 174, 226, 53, 222, 146, 162, 236, 158, 143, 55, 244, 233, 96, 173, 26, 206, 100, 227, 49, 178, 34, 234, 108, 207, 245, 204, 150, 44, 87, 121, 54, 140, 118, 221, 228, 155, 78, 3, 239, 101, 64, 102, 17, 223, 41, 137, 225, 229, 66, 116, 171, 125, 40, 39, 71, 134, 13, 193, 129, 247, 251, 20, 136, 242, 14, 36, 97, 163, 181, 72, 25, 144, 46, 175, 89, 145, 113, 90, 159, 190, 15, 183, 73, 123, 187, 128, 248, 252, 152, 24, 197, 68, 253, 52, 69, 117, 57, 92, 104, 157, 170, 214, 81, 60, 133, 208, 246, 172, 23, 167, 160, 192, 76, 161, 237, 45, 4, 58, 10, 182, 65, 202, 240, 185, 241, 79, 224, 132, 51, 42, 126, 105, 37, 250, 149, 32, 243, 231, 67, 179, 48, 9, 106, 216, 31, 249, 19, 85, 254, 156, 115, 255, 120, 75, 16 ] + [ + 60, 53, 84, 138, 217, 94, 88, 23, 39, 242, 219, 35, 12, 157, 165, 181, 255, + 143, 83, 247, 162, 16, 31, 209, 190, 171, 115, 65, 38, 41, 21, 245, 236, 46, + 121, 62, 166, 233, 44, 154, 153, 145, 230, 49, 128, 216, 173, 29, 241, 119, + 64, 229, 194, 103, 131, 110, 26, 197, 218, 59, 204, 56, 27, 34, 141, 221, + 149, 239, 192, 195, 24, 155, 170, 183, 11, 254, 213, 37, 137, 226, 75, 203, + 55, 19, 72, 248, 22, 129, 33, 175, 178, 10, 198, 71, 77, 36, 113, 167, 48, + 2, 117, 140, 142, 66, 199, 232, 243, 32, 123, 54, 51, 82, 57, 177, 87, 251, + 150, 196, 133, 5, 253, 130, 8, 184, 14, 152, 231, 3, 186, 159, 76, 89, 228, + 205, 156, 96, 163, 146, 18, 91, 132, 85, 80, 109, 172, 176, 105, 13, 50, + 235, 127, 0, 189, 95, 98, 136, 250, 200, 108, 179, 211, 214, 106, 168, 78, + 79, 74, 210, 30, 73, 201, 151, 208, 114, 101, 174, 92, 52, 120, 240, 15, + 169, 220, 182, 81, 224, 43, 185, 40, 99, 180, 17, 212, 158, 42, 90, 9, 191, + 45, 6, 25, 4, 222, 67, 126, 1, 116, 124, 206, 69, 61, 7, 68, 97, 202, 63, + 244, 20, 28, 58, 93, 134, 104, 144, 227, 147, 102, 118, 135, 148, 47, 238, + 86, 112, 122, 70, 107, 215, 100, 139, 223, 225, 164, 237, 111, 125, 207, + 160, 187, 246, 234, 161, 188, 193, 249, 252, + ], + [ + 151, 205, 99, 127, 201, 119, 199, 211, 122, 196, 91, 74, 12, 147, 124, 180, + 21, 191, 138, 83, 217, 30, 86, 7, 70, 200, 56, 62, 218, 47, 168, 22, 107, + 88, 63, 11, 95, 77, 28, 8, 188, 29, 194, 186, 38, 198, 33, 230, 98, 43, 148, + 110, 177, 1, 109, 82, 61, 112, 219, 59, 0, 210, 35, 215, 50, 27, 103, 203, + 212, 209, 235, 93, 84, 169, 166, 80, 130, 94, 164, 165, 142, 184, 111, 18, + 2, 141, 232, 114, 6, 131, 195, 139, 176, 220, 5, 153, 135, 213, 154, 189, + 238, 174, 226, 53, 222, 146, 162, 236, 158, 143, 55, 244, 233, 96, 173, 26, + 206, 100, 227, 49, 178, 34, 234, 108, 207, 245, 204, 150, 44, 87, 121, 54, + 140, 118, 221, 228, 155, 78, 3, 239, 101, 64, 102, 17, 223, 41, 137, 225, + 229, 66, 116, 171, 125, 40, 39, 71, 134, 13, 193, 129, 247, 251, 20, 136, + 242, 14, 36, 97, 163, 181, 72, 25, 144, 46, 175, 89, 145, 113, 90, 159, 190, + 15, 183, 73, 123, 187, 128, 248, 252, 152, 24, 197, 68, 253, 52, 69, 117, + 57, 92, 104, 157, 170, 214, 81, 60, 133, 208, 246, 172, 23, 167, 160, 192, + 76, 161, 237, 45, 4, 58, 10, 182, 65, 202, 240, 185, 241, 79, 224, 132, 51, + 42, 126, 105, 37, 250, 149, 32, 243, 231, 67, 179, 48, 9, 106, 216, 31, 249, + 19, 85, 254, 156, 115, 255, 120, 75, 16, + ], ]; const tables = encrypt.getTable('foobar!'); console.log(JSON.stringify(tables)); @@ -22,14 +56,14 @@ const server = child_process.spawn(process.execPath, ['server.js']); let curlRunning = false; -local.on('exit', function(code) { +local.on('exit', function (code) { server.kill(); if (!curlRunning) { process.exit(code); } }); -server.on('exit', function(code) { +server.on('exit', function (code) { local.kill(); if (!curlRunning) { process.exit(code); @@ -40,16 +74,16 @@ let localReady = false; let serverReady = false; curlRunning = false; -const runCurl = function() { +const runCurl = function () { curlRunning = true; const curl = child_process.spawn('curl', [ '-v', 'http://127.0.0.1:8080', '-L', '--socks5', - '127.0.0.1:1080' + '127.0.0.1:1080', ]); - curl.on('exit', function(code) { + curl.on('exit', function (code) { local.kill(); server.kill(); if (code === 0) { @@ -61,16 +95,16 @@ const runCurl = function() { } }); - curl.stdout.on('data', data => console.log(data.toString())); + curl.stdout.on('data', (data) => console.log(data.toString())); - curl.stderr.on('data', data => console.warn(data.toString())); + curl.stderr.on('data', (data) => console.warn(data.toString())); }; -local.stderr.on('data', data => console.warn(data.toString())); +local.stderr.on('data', (data) => console.warn(data.toString())); -server.stderr.on('data', data => console.warn(data.toString())); +server.stderr.on('data', (data) => console.warn(data.toString())); -local.stdout.on('data', function(data) { +local.stdout.on('data', function (data) { console.log(data.toString()); if (data.toString().indexOf('listening at') >= 0) { localReady = true; @@ -80,7 +114,7 @@ local.stdout.on('data', function(data) { } }); -server.stdout.on('data', function(data) { +server.stdout.on('data', function (data) { console.log(data.toString()); if (data.toString().indexOf('listening at') >= 0) { serverReady = true; From 64b47ec33cdc6b147aaf4e010fa9e621e1872b77 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 10:38:21 +0800 Subject: [PATCH 59/76] commonjs -> esm --- encrypt.js | 5 ++--- local.js | 19 +++++++++---------- package.json | 1 + server.js | 17 ++++++++--------- test.js | 6 ++++-- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/encrypt.js b/encrypt.js index 4b9d3787..a32f3429 100644 --- a/encrypt.js +++ b/encrypt.js @@ -1,4 +1,4 @@ -const crypto = require('crypto'); +import crypto from 'crypto'; const int32Max = Math.pow(2, 32); const cachedTables = {}; // password: [encryptTable, decryptTable] @@ -191,5 +191,4 @@ class Encryptor { } } -exports.Encryptor = Encryptor; -exports.getTable = getTable; +export {Encryptor, getTable}; diff --git a/local.js b/local.js index e1924067..ad0bfbea 100644 --- a/local.js +++ b/local.js @@ -1,12 +1,11 @@ -const net = require('net'); -const url = require('url'); -const http = require('http'); -const fs = require('fs'); -const path = require('path'); -const WebSocket = require('ws'); -const parseArgs = require('minimist'); -const {HttpsProxyAgent} = require('https-proxy-agent'); -const {Encryptor} = require('./encrypt'); +import net from 'net'; +import url from 'url'; +import http from 'http'; +import fs from 'fs'; +import WebSocket from 'ws'; +import parseArgs from 'minimist'; +import {HttpsProxyAgent} from 'https-proxy-agent'; +import {Encryptor} from './encrypt.js'; const options = { alias: { @@ -27,7 +26,7 @@ const options = { 'scheme', ], default: { - config_file: path.resolve(__dirname, 'config.json'), + config_file: './config.json', }, }; diff --git a/package.json b/package.json index 4d198f77..571ea84e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "shadowsocks-heroku", "version": "0.9.10", + "type": "module", "dependencies": { "bufferutil": "^4.0.1", "https-proxy-agent": "^7.0.4", diff --git a/server.js b/server.js index a830aab9..eadc45a3 100644 --- a/server.js +++ b/server.js @@ -1,11 +1,10 @@ -const net = require('net'); -const fs = require('fs'); -const path = require('path'); -const http = require('http'); -const WebSocket = require('ws'); -const WebSocketServer = WebSocket.Server; -const parseArgs = require('minimist'); -const {Encryptor} = require('./encrypt'); +import net from 'net'; +import fs from 'fs'; +import http from 'http'; +import WebSocket from 'ws'; +import { WebSocketServer } from 'ws'; +import parseArgs from 'minimist'; +import {Encryptor} from './encrypt.js'; const options = { alias: { @@ -17,7 +16,7 @@ const options = { }, string: ['local_address', 'password', 'method', 'config_file'], default: { - config_file: path.resolve(__dirname, 'config.json'), + config_file: './config.json', }, }; diff --git a/test.js b/test.js index d53b4665..ff6e9242 100644 --- a/test.js +++ b/test.js @@ -1,5 +1,6 @@ // test encryption -const encrypt = require('./encrypt'); +import * as encrypt from './encrypt.js'; + const target = [ [ 60, 53, 84, 138, 217, 94, 88, 23, 39, 242, 219, 35, 12, 157, 165, 181, 255, @@ -50,7 +51,8 @@ while (i < 256) { // test proxy -const child_process = require('child_process'); +import child_process from 'child_process'; + const local = child_process.spawn(process.execPath, ['local.js']); const server = child_process.spawn(process.execPath, ['server.js']); From 9354a3fc7670b5910423c82a318cec407bc8c492 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 11:05:58 +0800 Subject: [PATCH 60/76] (node:19613) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. --- encrypt.js | 4 ++-- local.js | 10 +++++----- server.js | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/encrypt.js b/encrypt.js index a32f3429..58653c9c 100644 --- a/encrypt.js +++ b/encrypt.js @@ -12,7 +12,7 @@ const getTable = function (key) { const decrypt_table = new Array(256); const md5sum = crypto.createHash('md5'); md5sum.update(key); - const hash = new Buffer(md5sum.digest(), 'binary'); + const hash = Buffer.from(md5sum.digest(), 'binary'); const al = hash.readUInt32LE(0); const ah = hash.readUInt32LE(4); let i = 0; @@ -135,7 +135,7 @@ class Encryptor { get_cipher(password, method, op, iv) { method = method.toLowerCase(); - password = new Buffer(password, 'binary'); + password = Buffer.from(password, 'binary'); const m = this.get_cipher_len(method); if (m) { const [key, iv_] = EVP_BytesToKey(password, m[0], m[1]); diff --git a/local.js b/local.js index ad0bfbea..8fb78226 100644 --- a/local.js +++ b/local.js @@ -115,7 +115,7 @@ var server = net.createServer(function (connection) { return; } if (stage === 0) { - const tempBuf = new Buffer(2); + const tempBuf = Buffer.alloc(2); tempBuf.write('\u0005\u0000', 0); connection.write(tempBuf); stage = 1; @@ -134,7 +134,7 @@ var server = net.createServer(function (connection) { const addrtype = data[3]; if (cmd !== 1) { console.log('unsupported cmd:', cmd); - const reply = new Buffer('\u0005\u0007\u0000\u0001', 'binary'); + const reply = Buffer.from('\u0005\u0007\u0000\u0001', 'binary'); connection.end(reply); return; } @@ -158,7 +158,7 @@ var server = net.createServer(function (connection) { remotePort = data.readUInt16BE(5 + addrLen); headerLength = 5 + addrLen + 2; } - let buf = new Buffer(10); + let buf = Buffer.alloc(10); buf.write('\u0005\u0000\u0000\u0001', 0, 4, 'binary'); buf.write('\u0000\u0000\u0000\u0000', 4, 4, 'binary'); buf.writeUInt16BE(remotePort, 8); @@ -195,7 +195,7 @@ var server = net.createServer(function (connection) { ws.on('open', function () { console.log(`connecting ${remoteAddr} via ${aServer}`); - let addrToSendBuf = new Buffer(addrToSend, 'binary'); + let addrToSendBuf = Buffer.from(addrToSend, 'binary'); addrToSendBuf = encryptor.encrypt(addrToSendBuf); ws.send(addrToSendBuf, {binary: true}); let i = 0; @@ -232,7 +232,7 @@ var server = net.createServer(function (connection) { }); if (data.length > headerLength) { - buf = new Buffer(data.length - headerLength); + buf = Buffer.alloc(data.length - headerLength); data.copy(buf, 0, headerLength); cachedPieces.push(buf); buf = null; diff --git a/server.js b/server.js index eadc45a3..8ff541b4 100644 --- a/server.js +++ b/server.js @@ -134,7 +134,7 @@ wss.on('connection', function (ws) { if (data.length > headerLength) { // make sure no data is lost - let buf = new Buffer(data.length - headerLength); + let buf = Buffer.alloc(data.length - headerLength); data.copy(buf, 0, headerLength); cachedPieces.push(buf); buf = null; From a4e6068bce3f9981cc08ab36e1111604aa0f18c5 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 13:37:13 +0800 Subject: [PATCH 61/76] IPv6 --- local.js | 23 ++++++++++++++++++++--- server.js | 28 ++++++++++++++++++++++------ test.js | 2 +- 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/local.js b/local.js index 8fb78226..6ece1f40 100644 --- a/local.js +++ b/local.js @@ -30,7 +30,17 @@ const options = { }, }; -const inetNtoa = (buf) => buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; +const inetNtoa = function (family, buf) { + if (family === 4) return buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; + else if (family === 6) { + let str = Buffer.alloc(0); + for (let i = 0; i < 8; i++) { + str += buf.readUInt16BE(i * 2, i * 2 + 2).toString(16); + if (i < 7) str += ':'; + } + return str; + } +}; const configFromArgs = parseArgs(process.argv.slice(2), options); const configContent = fs.readFileSync(configFromArgs.config_file); @@ -140,7 +150,7 @@ var server = net.createServer(function (connection) { } if (addrtype === 3) { addrLen = data[4]; - } else if (addrtype !== 1) { + } else if (addrtype !== 1 && addrtype !== 4) { console.log('unsupported addrtype:', addrtype); connection.end(); return; @@ -148,10 +158,17 @@ var server = net.createServer(function (connection) { addrToSend = data.slice(3, 4).toString('binary'); // read address and port if (addrtype === 1) { - remoteAddr = inetNtoa(data.slice(4, 8)); + // ipv4 + remoteAddr = inetNtoa(4, data.slice(4, 8)); addrToSend += data.slice(4, 10).toString('binary'); remotePort = data.readUInt16BE(8); headerLength = 10; + } else if (addrtype === 4) { + // ipv6 + remoteAddr = inetNtoa(6, data.slice(4, 20)); + addrToSend += data.slice(4, 22).toString('binary'); + remotePort = data.readUInt16BE(20); + headerLength = 22; } else { remoteAddr = data.slice(5, 5 + addrLen).toString('binary'); addrToSend += data.slice(4, 5 + addrLen + 2).toString('binary'); diff --git a/server.js b/server.js index 8ff541b4..88ad8a42 100644 --- a/server.js +++ b/server.js @@ -2,7 +2,7 @@ import net from 'net'; import fs from 'fs'; import http from 'http'; import WebSocket from 'ws'; -import { WebSocketServer } from 'ws'; +import {WebSocketServer} from 'ws'; import parseArgs from 'minimist'; import {Encryptor} from './encrypt.js'; @@ -20,7 +20,17 @@ const options = { }, }; -const inetNtoa = (buf) => buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; +const inetNtoa = function (family, buf) { + if (family === 4) return buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; + else if (family === 6) { + let str = Buffer.alloc(0); + for (let i = 0; i < 8; i++) { + str += buf.readUInt16BE(i * 2, i * 2 + 2).toString(16); + if (i < 7) str += ':'; + } + return str; + } +}; const configFromArgs = parseArgs(process.argv.slice(2), options); const configFile = configFromArgs.config_file; @@ -80,23 +90,29 @@ wss.on('connection', function (ws) { const addrtype = data[0]; if (addrtype === 3) { addrLen = data[1]; - } else if (addrtype !== 1) { + } else if (addrtype !== 1 && addrtype !== 4) { console.warn(`unsupported addrtype: ${addrtype}`); ws.close(); return; } // read address and port if (addrtype === 1) { - remoteAddr = inetNtoa(data.slice(1, 5)); + // ipv4 + remoteAddr = inetNtoa(4, data.slice(1, 5)); remotePort = data.readUInt16BE(5); - headerLength = 7; + headerLength = 1 + 4 + 2; + } else if (addrtype === 4) { + // ipv6 + remoteAddr = inetNtoa(6, data.slice(1, 17)); + remotePort = data.readUInt16BE(17); + headerLength = 1 + 16 + 2; } else { remoteAddr = data.slice(2, 2 + addrLen).toString('binary'); remotePort = data.readUInt16BE(2 + addrLen); headerLength = 2 + addrLen + 2; } - // connect remote server + // connect to remote server remote = net.connect(remotePort, remoteAddr, function () { console.log('connecting', remoteAddr); let i = 0; diff --git a/test.js b/test.js index ff6e9242..ec2ff415 100644 --- a/test.js +++ b/test.js @@ -80,7 +80,7 @@ const runCurl = function () { curlRunning = true; const curl = child_process.spawn('curl', [ '-v', - 'http://127.0.0.1:8080', + 'https://example.com', '-L', '--socks5', '127.0.0.1:1080', From 30ae59c98627925bbb143e38e01e8c6ce26760f9 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 13:51:40 +0800 Subject: [PATCH 62/76] Remove rc4* --- README.md | 8 +++----- encrypt.js | 24 +++--------------------- 2 files changed, 6 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index de2217a3..d40c5ea4 100644 --- a/README.md +++ b/README.md @@ -34,10 +34,10 @@ To git@heroku.com:still-tor-8707.git Set a few configs: ``` -$ heroku config:set METHOD=rc4 KEY=foobar +$ heroku config:set METHOD=table KEY=foobar Setting config vars and restarting still-tor-8707... done, v11 KEY: foobar -METHOD: rc4 +METHOD: table ``` Install project dependencies with `npm install`: @@ -50,7 +50,7 @@ $ npm install Then run: ``` -$ node local.js -s still-tor-8707.herokuapp.com -l 1080 -m rc4 -k foobar -r 80 +$ node local.js -s still-tor-8707.herokuapp.com -l 1080 -m table -k foobar -r 80 server listening at { address: '127.0.0.1', family: 'IPv4', port: 1080 } ``` @@ -71,8 +71,6 @@ $ heroku logs -t --app still-tor-8707 Supported Ciphers ----------------- -- rc4 -- rc4-md5 - table - bf-cfb - des-cfb diff --git a/encrypt.js b/encrypt.js index 58653c9c..b49da7d3 100644 --- a/encrypt.js +++ b/encrypt.js @@ -91,23 +91,9 @@ const method_supported = { 'des-cfb': [8, 8], 'idea-cfb': [16, 8], 'rc2-cfb': [16, 8], - rc4: [16, 0], - 'rc4-md5': [16, 16], 'seed-cfb': [16, 16], }; -const create_rc4_md5_cipher = function (key, iv, op) { - const md5 = crypto.createHash('md5'); - md5.update(key); - md5.update(iv); - const rc4_key = md5.digest(); - if (op === 1) { - return crypto.createCipheriv('rc4', rc4_key, ''); - } else { - return crypto.createDecipheriv('rc4', rc4_key, ''); - } -}; - class Encryptor { constructor(key, method) { this.key = key; @@ -146,14 +132,10 @@ class Encryptor { this.cipher_iv = iv.slice(0, m[1]); } iv = iv.slice(0, m[1]); - if (method === 'rc4-md5') { - return create_rc4_md5_cipher(key, iv, op); + if (op === 1) { + return crypto.createCipheriv(method, key, iv); } else { - if (op === 1) { - return crypto.createCipheriv(method, key, iv); - } else { - return crypto.createDecipheriv(method, key, iv); - } + return crypto.createDecipheriv(method, key, iv); } } } From 44f8e217764a8f40580c33e7f71438f1b2938ca2 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 15:30:37 +0800 Subject: [PATCH 63/76] Remove ping. --- local.js | 7 +------ server.js | 10 ++++++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/local.js b/local.js index 6ece1f40..df8f8614 100644 --- a/local.js +++ b/local.js @@ -110,7 +110,6 @@ var server = net.createServer(function (connection) { let cachedPieces = []; let addrLen = 0; let ws = null; - let ping = null; let remoteAddr = null; let remotePort = null; let addrToSend = ''; @@ -225,8 +224,6 @@ var server = net.createServer(function (connection) { } cachedPieces = null; // save memory stage = 5; - - ping = setInterval(() => ws.ping('', null, () => true), 50 * 1000); }); ws.on('message', function (data, flags) { @@ -235,7 +232,6 @@ var server = net.createServer(function (connection) { }); ws.on('close', function () { - clearInterval(ping); console.log('remote disconnected'); connection.destroy(); }); @@ -249,10 +245,9 @@ var server = net.createServer(function (connection) { }); if (data.length > headerLength) { - buf = Buffer.alloc(data.length - headerLength); + let buf = Buffer.alloc(data.length - headerLength); data.copy(buf, 0, headerLength); cachedPieces.push(buf); - buf = null; } stage = 4; } catch (error) { diff --git a/server.js b/server.js index 88ad8a42..50b11f69 100644 --- a/server.js +++ b/server.js @@ -67,7 +67,12 @@ const server = http.createServer(function (req, res) { res.end('asdf.'); }); -const wss = new WebSocketServer({server}); +const wss = new WebSocketServer({ + server, + autoPong: true, + allowSynchronousEvents: true, + perMessageDeflate: false, +}); wss.on('connection', function (ws) { console.log('server connected'); @@ -153,7 +158,6 @@ wss.on('connection', function (ws) { let buf = Buffer.alloc(data.length - headerLength); data.copy(buf, 0, headerLength); cachedPieces.push(buf); - buf = null; } stage = 4; } catch (error) { @@ -173,8 +177,6 @@ wss.on('connection', function (ws) { } }); - ws.on('ping', () => ws.pong('', null, true)); - ws.on('close', function () { console.log('server disconnected'); console.log('concurrent connections:', wss.clients.size); From 7a17132de010fc82186b380d3213383ed6daba00 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 19:07:57 +0800 Subject: [PATCH 64/76] Handles backpressure. --- server.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/server.js b/server.js index 50b11f69..1d621b78 100644 --- a/server.js +++ b/server.js @@ -57,6 +57,7 @@ const LOCAL_ADDRESS = config.local_address; const PORT = config.remote_port; const KEY = config.password; let METHOD = config.method; +const highWaterMark = +process.env.HIGH_WATER_MARK || 64 * 1024; if (['', 'null', 'table'].includes(METHOD.toLowerCase())) { METHOD = null; @@ -131,9 +132,15 @@ wss.on('connection', function (ws) { stage = 5; }); remote.on('data', function (data) { - data = encryptor.encrypt(data); if (ws.readyState === WebSocket.OPEN) { - ws.send(data, {binary: true}); + data = encryptor.encrypt(data); + ws.send(data, {binary: true}, (err) => { + if (err) return; + if (ws.bufferedAmount < highWaterMark && remote.isPaused()) + remote.resume(); + }); + if (ws.bufferedAmount >= highWaterMark && !remote.isPaused()) + remote.pause(); } }); From 66f06ac722b9bb5286f71de3ee1783168b93888e Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 19:11:05 +0800 Subject: [PATCH 65/76] Buffer.concat(cachedPieces) --- local.js | 11 +++-------- server.js | 8 +------- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/local.js b/local.js index df8f8614..6dc83b80 100644 --- a/local.js +++ b/local.js @@ -214,14 +214,9 @@ var server = net.createServer(function (connection) { let addrToSendBuf = Buffer.from(addrToSend, 'binary'); addrToSendBuf = encryptor.encrypt(addrToSendBuf); ws.send(addrToSendBuf, {binary: true}); - let i = 0; - - while (i < cachedPieces.length) { - let piece = cachedPieces[i]; - piece = encryptor.encrypt(piece); - ws.send(piece, {binary: true}); - i++; - } + ws.send(encryptor.encrypt(Buffer.concat(cachedPieces)), { + binary: true, + }); cachedPieces = null; // save memory stage = 5; }); diff --git a/server.js b/server.js index 1d621b78..ee191fef 100644 --- a/server.js +++ b/server.js @@ -121,13 +121,7 @@ wss.on('connection', function (ws) { // connect to remote server remote = net.connect(remotePort, remoteAddr, function () { console.log('connecting', remoteAddr); - let i = 0; - - while (i < cachedPieces.length) { - const piece = cachedPieces[i]; - remote.write(piece); - i++; - } + remote.write(Buffer.concat(cachedPieces)); cachedPieces = null; // save memory stage = 5; }); From 1879333e7bf7d6d3c7ce081d5c843e8995740968 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 20:13:53 +0800 Subject: [PATCH 66/76] Remove table cipher. --- README.md | 19 +++------ encrypt.js | 113 +++++++++-------------------------------------------- local.js | 5 --- server.js | 4 -- test.js | 51 ------------------------ 5 files changed, 24 insertions(+), 168 deletions(-) diff --git a/README.md b/README.md index d40c5ea4..0c30e7c5 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ shadowsocks-heroku is a lightweight tunnel proxy which can help you get through shadowsocks-heroku uses WebSocket instead of raw sockets, so it can be deployed on [Heroku](https://www.heroku.com/). -Notice that the protocol is INCOMPATIBLE with the origin shadowsocks. +Notice that the protocol is INCOMPATIBLE with shadowsocks. Heroku ------ @@ -34,10 +34,10 @@ To git@heroku.com:still-tor-8707.git Set a few configs: ``` -$ heroku config:set METHOD=table KEY=foobar +$ heroku config:set METHOD=aes-128-cfb KEY=foobar Setting config vars and restarting still-tor-8707... done, v11 KEY: foobar -METHOD: table +METHOD: aes-128-cfb ``` Install project dependencies with `npm install`: @@ -50,7 +50,7 @@ $ npm install Then run: ``` -$ node local.js -s still-tor-8707.herokuapp.com -l 1080 -m table -k foobar -r 80 +$ node local.js -s still-tor-8707.herokuapp.com -l 1080 -m aes-128-cfb -k foobar -r 80 server listening at { address: '127.0.0.1', family: 'IPv4', port: 1080 } ``` @@ -71,16 +71,9 @@ $ heroku logs -t --app still-tor-8707 Supported Ciphers ----------------- -- table -- bf-cfb -- des-cfb -- rc2-cfb -- idea-cfb -- seed-cfb -- cast5-cfb - aes-128-cfb - aes-192-cfb - aes-256-cfb -- camellia-256-cfb -- camellia-192-cfb - camellia-128-cfb +- camellia-192-cfb +- camellia-256-cfb diff --git a/encrypt.js b/encrypt.js index b49da7d3..6f9ed351 100644 --- a/encrypt.js +++ b/encrypt.js @@ -1,55 +1,4 @@ import crypto from 'crypto'; -const int32Max = Math.pow(2, 32); - -const cachedTables = {}; // password: [encryptTable, decryptTable] - -const getTable = function (key) { - if (cachedTables[key]) { - return cachedTables[key]; - } - console.log('calculating ciphers'); - let table = new Array(256); - const decrypt_table = new Array(256); - const md5sum = crypto.createHash('md5'); - md5sum.update(key); - const hash = Buffer.from(md5sum.digest(), 'binary'); - const al = hash.readUInt32LE(0); - const ah = hash.readUInt32LE(4); - let i = 0; - - while (i < 256) { - table[i] = i; - i++; - } - i = 1; - - while (i < 1024) { - table.sort( - (x, y) => - (((ah % (x + i)) * int32Max + al) % (x + i)) - - (((ah % (y + i)) * int32Max + al) % (y + i)), - ); - i++; - } - i = 0; - while (i < 256) { - decrypt_table[table[i]] = i; - ++i; - } - const result = [table, decrypt_table]; - cachedTables[key] = result; - return result; -}; - -const substitute = function (table, buf) { - let i = 0; - - while (i < buf.length) { - buf[i] = table[buf[i]]; - i++; - } - return buf; -}; const bytes_to_key_results = {}; @@ -83,35 +32,22 @@ const method_supported = { 'aes-128-cfb': [16, 16], 'aes-192-cfb': [24, 16], 'aes-256-cfb': [32, 16], - 'bf-cfb': [16, 8], 'camellia-128-cfb': [16, 16], 'camellia-192-cfb': [24, 16], 'camellia-256-cfb': [32, 16], - 'cast5-cfb': [16, 8], - 'des-cfb': [8, 8], - 'idea-cfb': [16, 8], - 'rc2-cfb': [16, 8], - 'seed-cfb': [16, 16], }; -class Encryptor { +export class Encryptor { constructor(key, method) { this.key = key; this.method = method; this.iv_sent = false; - if (this.method === 'table') { - this.method = null; - } - if (this.method) { - this.cipher = this.get_cipher( - this.key, - this.method, - 1, - crypto.randomBytes(32), - ); - } else { - [this.encryptTable, this.decryptTable] = getTable(this.key); - } + this.cipher = this.get_cipher( + this.key, + this.method, + 1, + crypto.randomBytes(32), + ); } get_cipher_len(method) { @@ -141,36 +77,23 @@ class Encryptor { } encrypt(buf) { - if (this.method) { - const result = this.cipher.update(buf); - if (this.iv_sent) { - return result; - } else { - this.iv_sent = true; - return Buffer.concat([this.cipher_iv, result]); - } + const result = this.cipher.update(buf); + if (this.iv_sent) { + return result; } else { - return substitute(this.encryptTable, buf); + this.iv_sent = true; + return Buffer.concat([this.cipher_iv, result]); } } decrypt(buf) { - if (this.method) { - let result; - if (!this.decipher) { - const decipher_iv_len = this.get_cipher_len(this.method)[1]; - const decipher_iv = buf.slice(0, decipher_iv_len); - this.decipher = this.get_cipher(this.key, this.method, 0, decipher_iv); - result = this.decipher.update(buf.slice(decipher_iv_len)); - return result; - } else { - result = this.decipher.update(buf); - return result; - } + if (!this.decipher) { + const decipher_iv_len = this.get_cipher_len(this.method)[1]; + const decipher_iv = buf.slice(0, decipher_iv_len); + this.decipher = this.get_cipher(this.key, this.method, 0, decipher_iv); + return this.decipher.update(buf.slice(decipher_iv_len)); } else { - return substitute(this.decryptTable, buf); + return this.decipher.update(buf); } } } - -export {Encryptor, getTable}; diff --git a/local.js b/local.js index 6dc83b80..2124e5fe 100644 --- a/local.js +++ b/local.js @@ -58,11 +58,6 @@ const PORT = config.local_port; const KEY = config.password; let METHOD = config.method; const timeout = Math.floor(config.timeout * 1000); - -if (['', 'null', 'table'].includes(METHOD.toLowerCase())) { - METHOD = null; -} - const HTTPPROXY = process.env.http_proxy; if (HTTPPROXY) { diff --git a/server.js b/server.js index ee191fef..58b63bb5 100644 --- a/server.js +++ b/server.js @@ -59,10 +59,6 @@ const KEY = config.password; let METHOD = config.method; const highWaterMark = +process.env.HIGH_WATER_MARK || 64 * 1024; -if (['', 'null', 'table'].includes(METHOD.toLowerCase())) { - METHOD = null; -} - const server = http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/plain'}); res.end('asdf.'); diff --git a/test.js b/test.js index ec2ff415..ec877bf5 100644 --- a/test.js +++ b/test.js @@ -1,54 +1,3 @@ -// test encryption -import * as encrypt from './encrypt.js'; - -const target = [ - [ - 60, 53, 84, 138, 217, 94, 88, 23, 39, 242, 219, 35, 12, 157, 165, 181, 255, - 143, 83, 247, 162, 16, 31, 209, 190, 171, 115, 65, 38, 41, 21, 245, 236, 46, - 121, 62, 166, 233, 44, 154, 153, 145, 230, 49, 128, 216, 173, 29, 241, 119, - 64, 229, 194, 103, 131, 110, 26, 197, 218, 59, 204, 56, 27, 34, 141, 221, - 149, 239, 192, 195, 24, 155, 170, 183, 11, 254, 213, 37, 137, 226, 75, 203, - 55, 19, 72, 248, 22, 129, 33, 175, 178, 10, 198, 71, 77, 36, 113, 167, 48, - 2, 117, 140, 142, 66, 199, 232, 243, 32, 123, 54, 51, 82, 57, 177, 87, 251, - 150, 196, 133, 5, 253, 130, 8, 184, 14, 152, 231, 3, 186, 159, 76, 89, 228, - 205, 156, 96, 163, 146, 18, 91, 132, 85, 80, 109, 172, 176, 105, 13, 50, - 235, 127, 0, 189, 95, 98, 136, 250, 200, 108, 179, 211, 214, 106, 168, 78, - 79, 74, 210, 30, 73, 201, 151, 208, 114, 101, 174, 92, 52, 120, 240, 15, - 169, 220, 182, 81, 224, 43, 185, 40, 99, 180, 17, 212, 158, 42, 90, 9, 191, - 45, 6, 25, 4, 222, 67, 126, 1, 116, 124, 206, 69, 61, 7, 68, 97, 202, 63, - 244, 20, 28, 58, 93, 134, 104, 144, 227, 147, 102, 118, 135, 148, 47, 238, - 86, 112, 122, 70, 107, 215, 100, 139, 223, 225, 164, 237, 111, 125, 207, - 160, 187, 246, 234, 161, 188, 193, 249, 252, - ], - [ - 151, 205, 99, 127, 201, 119, 199, 211, 122, 196, 91, 74, 12, 147, 124, 180, - 21, 191, 138, 83, 217, 30, 86, 7, 70, 200, 56, 62, 218, 47, 168, 22, 107, - 88, 63, 11, 95, 77, 28, 8, 188, 29, 194, 186, 38, 198, 33, 230, 98, 43, 148, - 110, 177, 1, 109, 82, 61, 112, 219, 59, 0, 210, 35, 215, 50, 27, 103, 203, - 212, 209, 235, 93, 84, 169, 166, 80, 130, 94, 164, 165, 142, 184, 111, 18, - 2, 141, 232, 114, 6, 131, 195, 139, 176, 220, 5, 153, 135, 213, 154, 189, - 238, 174, 226, 53, 222, 146, 162, 236, 158, 143, 55, 244, 233, 96, 173, 26, - 206, 100, 227, 49, 178, 34, 234, 108, 207, 245, 204, 150, 44, 87, 121, 54, - 140, 118, 221, 228, 155, 78, 3, 239, 101, 64, 102, 17, 223, 41, 137, 225, - 229, 66, 116, 171, 125, 40, 39, 71, 134, 13, 193, 129, 247, 251, 20, 136, - 242, 14, 36, 97, 163, 181, 72, 25, 144, 46, 175, 89, 145, 113, 90, 159, 190, - 15, 183, 73, 123, 187, 128, 248, 252, 152, 24, 197, 68, 253, 52, 69, 117, - 57, 92, 104, 157, 170, 214, 81, 60, 133, 208, 246, 172, 23, 167, 160, 192, - 76, 161, 237, 45, 4, 58, 10, 182, 65, 202, 240, 185, 241, 79, 224, 132, 51, - 42, 126, 105, 37, 250, 149, 32, 243, 231, 67, 179, 48, 9, 106, 216, 31, 249, - 19, 85, 254, 156, 115, 255, 120, 75, 16, - ], -]; -const tables = encrypt.getTable('foobar!'); -console.log(JSON.stringify(tables)); -let i = 0; - -while (i < 256) { - console.assert(tables[0][i] === target[0][i]); - console.assert(tables[1][i] === target[1][i]); - i++; -} - // test proxy import child_process from 'child_process'; From 6e887fd577cb743c53c739fd0211edbf75010104 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Tue, 5 Mar 2024 20:32:09 +0800 Subject: [PATCH 67/76] Move inetNtoa to utils. --- local.js | 13 +------------ server.js | 13 +------------ utils.js | 11 +++++++++++ 3 files changed, 13 insertions(+), 24 deletions(-) create mode 100644 utils.js diff --git a/local.js b/local.js index 2124e5fe..22b99034 100644 --- a/local.js +++ b/local.js @@ -6,6 +6,7 @@ import WebSocket from 'ws'; import parseArgs from 'minimist'; import {HttpsProxyAgent} from 'https-proxy-agent'; import {Encryptor} from './encrypt.js'; +import {inetNtoa} from './utils.js'; const options = { alias: { @@ -30,18 +31,6 @@ const options = { }, }; -const inetNtoa = function (family, buf) { - if (family === 4) return buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; - else if (family === 6) { - let str = Buffer.alloc(0); - for (let i = 0; i < 8; i++) { - str += buf.readUInt16BE(i * 2, i * 2 + 2).toString(16); - if (i < 7) str += ':'; - } - return str; - } -}; - const configFromArgs = parseArgs(process.argv.slice(2), options); const configContent = fs.readFileSync(configFromArgs.config_file); const config = JSON.parse(configContent); diff --git a/server.js b/server.js index 58b63bb5..a13ac5de 100644 --- a/server.js +++ b/server.js @@ -5,6 +5,7 @@ import WebSocket from 'ws'; import {WebSocketServer} from 'ws'; import parseArgs from 'minimist'; import {Encryptor} from './encrypt.js'; +import {inetNtoa} from './utils.js'; const options = { alias: { @@ -20,18 +21,6 @@ const options = { }, }; -const inetNtoa = function (family, buf) { - if (family === 4) return buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; - else if (family === 6) { - let str = Buffer.alloc(0); - for (let i = 0; i < 8; i++) { - str += buf.readUInt16BE(i * 2, i * 2 + 2).toString(16); - if (i < 7) str += ':'; - } - return str; - } -}; - const configFromArgs = parseArgs(process.argv.slice(2), options); const configFile = configFromArgs.config_file; const configContent = fs.readFileSync(configFile); diff --git a/utils.js b/utils.js new file mode 100644 index 00000000..dd1d11c7 --- /dev/null +++ b/utils.js @@ -0,0 +1,11 @@ +export function inetNtoa(family, buf) { + if (family === 4) return buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; + else if (family === 6) { + let str = Buffer.alloc(0); + for (let i = 0; i < 8; i++) { + str += buf.readUInt16BE(i * 2, i * 2 + 2).toString(16); + if (i < 7) str += ':'; + } + return str; + } +} From 28a149b2b5e5769e15e9cffebb24f381c315fd73 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Wed, 6 Mar 2024 12:25:43 +0800 Subject: [PATCH 68/76] test: Run server in the test process. --- local.js | 2 ++ server.js | 2 ++ test.js | 68 ++++++++++++------------------------------------------- 3 files changed, 18 insertions(+), 54 deletions(-) diff --git a/local.js b/local.js index 22b99034..961870e9 100644 --- a/local.js +++ b/local.js @@ -283,3 +283,5 @@ server.on('error', function (e) { } process.exit(1); }); + +export default server; diff --git a/server.js b/server.js index a13ac5de..63a79d7f 100644 --- a/server.js +++ b/server.js @@ -191,3 +191,5 @@ server.on('error', function (e) { } process.exit(1); }); + +export default server; diff --git a/test.js b/test.js index ec877bf5..84fed0ca 100644 --- a/test.js +++ b/test.js @@ -1,32 +1,8 @@ -// test proxy - import child_process from 'child_process'; +import local from './local.js'; +import server from './server.js'; -const local = child_process.spawn(process.execPath, ['local.js']); -const server = child_process.spawn(process.execPath, ['server.js']); - -let curlRunning = false; - -local.on('exit', function (code) { - server.kill(); - if (!curlRunning) { - process.exit(code); - } -}); - -server.on('exit', function (code) { - local.kill(); - if (!curlRunning) { - process.exit(code); - } -}); - -let localReady = false; -let serverReady = false; -curlRunning = false; - -const runCurl = function () { - curlRunning = true; +async function runCurl() { const curl = child_process.spawn('curl', [ '-v', 'https://example.com', @@ -35,8 +11,6 @@ const runCurl = function () { '127.0.0.1:1080', ]); curl.on('exit', function (code) { - local.kill(); - server.kill(); if (code === 0) { console.log('Test passed'); process.exit(0); @@ -46,31 +20,17 @@ const runCurl = function () { } }); - curl.stdout.on('data', (data) => console.log(data.toString())); + curl.stdout.pipe(process.stdout); + curl.stderr.pipe(process.stderr); - curl.stderr.on('data', (data) => console.warn(data.toString())); -}; - -local.stderr.on('data', (data) => console.warn(data.toString())); - -server.stderr.on('data', (data) => console.warn(data.toString())); - -local.stdout.on('data', function (data) { - console.log(data.toString()); - if (data.toString().indexOf('listening at') >= 0) { - localReady = true; - if (localReady && serverReady && !curlRunning) { - runCurl(); - } - } -}); + await new Promise((r) => { + curl.on('close', r); + }); +} -server.stdout.on('data', function (data) { - console.log(data.toString()); - if (data.toString().indexOf('listening at') >= 0) { - serverReady = true; - if (localReady && serverReady && !curlRunning) { - runCurl(); - } +while (true) { + if (local.listening && server.listening) { + await runCurl(); } -}); + await new Promise((r) => setTimeout(r, 100)); +} From 8f19e8a78db4743d7c93a85cf79734d2672ea041 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Wed, 6 Mar 2024 13:11:29 +0800 Subject: [PATCH 69/76] Fix EVP_BytesToKey memoize. --- encrypt.js | 11 +++-------- utils.js | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/encrypt.js b/encrypt.js index 6f9ed351..6c79be6a 100644 --- a/encrypt.js +++ b/encrypt.js @@ -1,11 +1,7 @@ import crypto from 'crypto'; +import {memoize} from './utils.js'; -const bytes_to_key_results = {}; - -const EVP_BytesToKey = function (password, key_len, iv_len) { - if (bytes_to_key_results[`${password}:${key_len}:${iv_len}`]) { - return bytes_to_key_results[`${password}:${key_len}:${iv_len}`]; - } +const EVP_BytesToKey = memoize(function (password, key_len, iv_len) { const m = []; let i = 0; let count = 0; @@ -24,9 +20,8 @@ const EVP_BytesToKey = function (password, key_len, iv_len) { const ms = Buffer.concat(m); const key = ms.slice(0, key_len); const iv = ms.slice(key_len, key_len + iv_len); - bytes_to_key_results[password] = [key, iv]; return [key, iv]; -}; +}); const method_supported = { 'aes-128-cfb': [16, 16], diff --git a/utils.js b/utils.js index dd1d11c7..82e40602 100644 --- a/utils.js +++ b/utils.js @@ -9,3 +9,17 @@ export function inetNtoa(family, buf) { return str; } } + +export function memoize(func) { + const cache = {}; + + return function (...args) { + const key = args.join(''); + if (cache[key]) return cache[key]; + + const result = func.apply(this, args); + cache[key] = result; + + return result; + }; +} From c1fc88aef006bb852495ea669367aeef500d11d3 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Wed, 6 Mar 2024 18:29:01 +0800 Subject: [PATCH 70/76] Refactor huge try-catch by buffer length checking. --- local.js | 212 ++++++++++++++++++++++++++++-------------------------- server.js | 144 +++++++++++++++++++------------------ 2 files changed, 184 insertions(+), 172 deletions(-) diff --git a/local.js b/local.js index 961870e9..782e3c2e 100644 --- a/local.js +++ b/local.js @@ -90,9 +90,7 @@ var server = net.createServer(function (connection) { }); const encryptor = new Encryptor(KEY, METHOD); let stage = 0; - let headerLength = 0; let cachedPieces = []; - let addrLen = 0; let ws = null; let remoteAddr = null; let remotePort = null; @@ -115,126 +113,136 @@ var server = net.createServer(function (connection) { return; } if (stage === 1) { - try { - // +----+-----+-------+------+----------+----------+ - // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | - // +----+-----+-------+------+----------+----------+ - // | 1 | 1 | X'00' | 1 | Variable | 2 | - // +----+-----+-------+------+----------+----------+ + // +----+-----+-------+------+----------+----------+ + // |VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | + // +----+-----+-------+------+----------+----------+ + // | 1 | 1 | X'00' | 1 | Variable | 2 | + // +----+-----+-------+------+----------+----------+ - //cmd and addrtype - const cmd = data[1]; - const addrtype = data[3]; - if (cmd !== 1) { - console.log('unsupported cmd:', cmd); - const reply = Buffer.from('\u0005\u0007\u0000\u0001', 'binary'); - connection.end(reply); + let headerLength = 5; + + if (data.length < headerLength) { + connection.end(); + return; + } + const cmd = data[1]; + const addrtype = data[3]; + if (cmd !== 1) { + console.log('unsupported cmd:', cmd); + const reply = Buffer.from('\u0005\u0007\u0000\u0001', 'binary'); + connection.end(reply); + return; + } + if (![1, 3, 4].includes(addrtype)) { + console.log('unsupported addrtype:', addrtype); + connection.end(); + return; + } + addrToSend = data.slice(3, 4).toString('binary'); + + // read address and port + if (addrtype === 1) { + // ipv4 + headerLength = 4 + 4 + 2; + if (data.length < headerLength) { + connection.end(); return; } - if (addrtype === 3) { - addrLen = data[4]; - } else if (addrtype !== 1 && addrtype !== 4) { - console.log('unsupported addrtype:', addrtype); + remoteAddr = inetNtoa(4, data.slice(4, 8)); + addrToSend += data.slice(4, 10).toString('binary'); + remotePort = data.readUInt16BE(8); + } else if (addrtype === 4) { + // ipv6 + headerLength = 4 + 16 + 2; + if (data.length < headerLength) { connection.end(); return; } - addrToSend = data.slice(3, 4).toString('binary'); - // read address and port - if (addrtype === 1) { - // ipv4 - remoteAddr = inetNtoa(4, data.slice(4, 8)); - addrToSend += data.slice(4, 10).toString('binary'); - remotePort = data.readUInt16BE(8); - headerLength = 10; - } else if (addrtype === 4) { - // ipv6 - remoteAddr = inetNtoa(6, data.slice(4, 20)); - addrToSend += data.slice(4, 22).toString('binary'); - remotePort = data.readUInt16BE(20); - headerLength = 22; - } else { - remoteAddr = data.slice(5, 5 + addrLen).toString('binary'); - addrToSend += data.slice(4, 5 + addrLen + 2).toString('binary'); - remotePort = data.readUInt16BE(5 + addrLen); - headerLength = 5 + addrLen + 2; + remoteAddr = inetNtoa(6, data.slice(4, 20)); + addrToSend += data.slice(4, 22).toString('binary'); + remotePort = data.readUInt16BE(20); + } else { + const addrLen = data[4]; + headerLength = 5 + addrLen + 2; + if (data.length < headerLength) { + connection.end(); + return; } - let buf = Buffer.alloc(10); - buf.write('\u0005\u0000\u0000\u0001', 0, 4, 'binary'); - buf.write('\u0000\u0000\u0000\u0000', 4, 4, 'binary'); - buf.writeUInt16BE(remotePort, 8); - connection.write(buf); - // connect to remote server - // ws = new WebSocket aServer, protocol: "binary" + remoteAddr = data.slice(5, 5 + addrLen).toString('binary'); + addrToSend += data.slice(4, 5 + addrLen + 2).toString('binary'); + remotePort = data.readUInt16BE(5 + addrLen); + } + let buf = Buffer.alloc(10); + buf.write('\u0005\u0000\u0000\u0001', 0, 4, 'binary'); + buf.write('\u0000\u0000\u0000\u0000', 4, 4, 'binary'); + buf.writeUInt16BE(remotePort, 8); + connection.write(buf); + // connect to remote server + // ws = new WebSocket aServer, protocol: "binary" - if (HTTPPROXY) { - // WebSocket endpoint for the proxy to connect to - const endpoint = aServer; - const parsed = url.parse(endpoint); - //console.log('attempting to connect to WebSocket %j', endpoint); + if (HTTPPROXY) { + // WebSocket endpoint for the proxy to connect to + const endpoint = aServer; + const parsed = url.parse(endpoint); + //console.log('attempting to connect to WebSocket %j', endpoint); - // create an instance of the `HttpsProxyAgent` class with the proxy server information - const opts = url.parse(HTTPPROXY); + // create an instance of the `HttpsProxyAgent` class with the proxy server information + const opts = url.parse(HTTPPROXY); - // IMPORTANT! Set the `secureEndpoint` option to `false` when connecting - // over "ws://", but `true` when connecting over "wss://" - opts.secureEndpoint = parsed.protocol - ? parsed.protocol == 'wss:' - : false; + // IMPORTANT! Set the `secureEndpoint` option to `false` when connecting + // over "ws://", but `true` when connecting over "wss://" + opts.secureEndpoint = parsed.protocol + ? parsed.protocol == 'wss:' + : false; - const agent = new HttpsProxyAgent(opts); + const agent = new HttpsProxyAgent(opts); - ws = new WebSocket(aServer, { - protocol: 'binary', - agent, - }); - } else { - ws = new WebSocket(aServer, { - protocol: 'binary', - }); - } - - ws.on('open', function () { - console.log(`connecting ${remoteAddr} via ${aServer}`); - let addrToSendBuf = Buffer.from(addrToSend, 'binary'); - addrToSendBuf = encryptor.encrypt(addrToSendBuf); - ws.send(addrToSendBuf, {binary: true}); - ws.send(encryptor.encrypt(Buffer.concat(cachedPieces)), { - binary: true, - }); - cachedPieces = null; // save memory - stage = 5; + ws = new WebSocket(aServer, { + protocol: 'binary', + agent, }); - - ws.on('message', function (data, flags) { - data = encryptor.decrypt(data); - connection.write(data); + } else { + ws = new WebSocket(aServer, { + protocol: 'binary', }); + } - ws.on('close', function () { - console.log('remote disconnected'); - connection.destroy(); + ws.on('open', function () { + console.log(`connecting ${remoteAddr} via ${aServer}`); + let addrToSendBuf = Buffer.from(addrToSend, 'binary'); + addrToSendBuf = encryptor.encrypt(addrToSendBuf); + ws.send(addrToSendBuf, {binary: true}); + ws.send(encryptor.encrypt(Buffer.concat(cachedPieces)), { + binary: true, }); + cachedPieces = null; // save memory + stage = 5; + }); - ws.on('error', function (e) { - console.log(`remote ${remoteAddr}:${remotePort} error: ${e}`); - connection.destroy(); - server.getConnections(function (err, count) { - console.log('concurrent connections:', count); - }); - }); + ws.on('message', function (data, flags) { + data = encryptor.decrypt(data); + connection.write(data); + }); - if (data.length > headerLength) { - let buf = Buffer.alloc(data.length - headerLength); - data.copy(buf, 0, headerLength); - cachedPieces.push(buf); - } - stage = 4; - } catch (error) { - // may encounter index out of range - const e = error; - console.log(e); + ws.on('close', function () { + console.log('remote disconnected'); connection.destroy(); + }); + + ws.on('error', function (e) { + console.log(`remote ${remoteAddr}:${remotePort} error: ${e}`); + connection.destroy(); + server.getConnections(function (err, count) { + console.log('concurrent connections:', count); + }); + }); + + if (data.length > headerLength) { + let buf = Buffer.alloc(data.length - headerLength); + data.copy(buf, 0, headerLength); + cachedPieces.push(buf); } + stage = 4; } else if (stage === 4) { // remote server not connected // cache received buffers diff --git a/server.js b/server.js index 63a79d7f..7f78c257 100644 --- a/server.js +++ b/server.js @@ -65,10 +65,8 @@ wss.on('connection', function (ws) { console.log('concurrent connections:', wss.clients.size); const encryptor = new Encryptor(KEY, METHOD); let stage = 0; - let headerLength = 0; let remote = null; let cachedPieces = []; - let addrLen = 0; let remoteAddr = null; let remotePort = null; ws.on('message', function (data, flags) { @@ -77,84 +75,90 @@ wss.on('connection', function (ws) { remote.write(data); } if (stage === 0) { - try { - const addrtype = data[0]; - if (addrtype === 3) { - addrLen = data[1]; - } else if (addrtype !== 1 && addrtype !== 4) { - console.warn(`unsupported addrtype: ${addrtype}`); + let headerLength = 2; + if (data.length < headerLength) { + ws.close(); + return; + } + const addrtype = data[0]; + if (![1, 3, 4].includes(addrtype)) { + console.warn(`unsupported addrtype: ${addrtype}`); + ws.close(); + return; + } + // read address and port + if (addrtype === 1) { + // ipv4 + headerLength = 1 + 4 + 2; + if (data.length < headerLength) { ws.close(); return; } - // read address and port - if (addrtype === 1) { - // ipv4 - remoteAddr = inetNtoa(4, data.slice(1, 5)); - remotePort = data.readUInt16BE(5); - headerLength = 1 + 4 + 2; - } else if (addrtype === 4) { - // ipv6 - remoteAddr = inetNtoa(6, data.slice(1, 17)); - remotePort = data.readUInt16BE(17); - headerLength = 1 + 16 + 2; - } else { - remoteAddr = data.slice(2, 2 + addrLen).toString('binary'); - remotePort = data.readUInt16BE(2 + addrLen); - headerLength = 2 + addrLen + 2; + remoteAddr = inetNtoa(4, data.slice(1, 5)); + remotePort = data.readUInt16BE(5); + } else if (addrtype === 4) { + // ipv6 + headerLength = 1 + 16 + 2; + if (data.length < headerLength) { + ws.close(); + return; } - - // connect to remote server - remote = net.connect(remotePort, remoteAddr, function () { - console.log('connecting', remoteAddr); - remote.write(Buffer.concat(cachedPieces)); - cachedPieces = null; // save memory - stage = 5; - }); - remote.on('data', function (data) { - if (ws.readyState === WebSocket.OPEN) { - data = encryptor.encrypt(data); - ws.send(data, {binary: true}, (err) => { - if (err) return; - if (ws.bufferedAmount < highWaterMark && remote.isPaused()) - remote.resume(); - }); - if (ws.bufferedAmount >= highWaterMark && !remote.isPaused()) - remote.pause(); - } - }); - - remote.on('end', function () { + remoteAddr = inetNtoa(6, data.slice(1, 17)); + remotePort = data.readUInt16BE(17); + } else { + let addrLen = data[1]; + headerLength = 2 + addrLen + 2; + if (data.length < headerLength) { ws.close(); - console.log('remote disconnected'); - }); + return; + } + remoteAddr = data.slice(2, 2 + addrLen).toString('binary'); + remotePort = data.readUInt16BE(2 + addrLen); + } - remote.on('error', function (e) { - ws.terminate(); - console.log(`remote: ${e}`); - }); + // connect to remote server + remote = net.connect(remotePort, remoteAddr, function () { + console.log('connecting', remoteAddr); + remote.write(Buffer.concat(cachedPieces)); + cachedPieces = null; // save memory + stage = 5; + }); + remote.on('data', function (data) { + if (ws.readyState === WebSocket.OPEN) { + data = encryptor.encrypt(data); + ws.send(data, {binary: true}, (err) => { + if (err) return; + if (ws.bufferedAmount < highWaterMark && remote.isPaused()) + remote.resume(); + }); + if (ws.bufferedAmount >= highWaterMark && !remote.isPaused()) + remote.pause(); + } + }); - remote.setTimeout(timeout, function () { - console.log('remote timeout'); - remote.destroy(); - ws.close(); - }); + remote.on('end', function () { + ws.close(); + console.log('remote disconnected'); + }); - if (data.length > headerLength) { - // make sure no data is lost - let buf = Buffer.alloc(data.length - headerLength); - data.copy(buf, 0, headerLength); - cachedPieces.push(buf); - } - stage = 4; - } catch (error) { - // may encouter index out of range - const e = error; - console.warn(e); - if (remote) { - remote.destroy(); - } + remote.on('error', function (e) { + ws.terminate(); + console.log(`remote: ${e}`); + }); + + remote.setTimeout(timeout, function () { + console.log('remote timeout'); + remote.destroy(); ws.close(); + }); + + if (data.length > headerLength) { + // make sure no data is lost + let buf = Buffer.alloc(data.length - headerLength); + data.copy(buf, 0, headerLength); + cachedPieces.push(buf); } + stage = 4; } else if (stage === 4) { // remote server not connected // cache received buffers From 41e1bea3bedb1fc04bf0698d47e134f9c5663aad Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Sun, 10 Mar 2024 00:50:06 +0800 Subject: [PATCH 71/76] Send addr + data in one ws message. --- local.js | 18 ++++++++---------- server.js | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/local.js b/local.js index 782e3c2e..9332d0b8 100644 --- a/local.js +++ b/local.js @@ -106,9 +106,7 @@ var server = net.createServer(function (connection) { return; } if (stage === 0) { - const tempBuf = Buffer.alloc(2); - tempBuf.write('\u0005\u0000', 0); - connection.write(tempBuf); + connection.write(Buffer.from([5, 0])); stage = 1; return; } @@ -209,19 +207,19 @@ var server = net.createServer(function (connection) { ws.on('open', function () { console.log(`connecting ${remoteAddr} via ${aServer}`); - let addrToSendBuf = Buffer.from(addrToSend, 'binary'); - addrToSendBuf = encryptor.encrypt(addrToSendBuf); - ws.send(addrToSendBuf, {binary: true}); - ws.send(encryptor.encrypt(Buffer.concat(cachedPieces)), { + const data = Buffer.concat([ + Buffer.from(addrToSend, 'binary'), + ...cachedPieces, + ]); + cachedPieces = null; + ws.send(encryptor.encrypt(data), { binary: true, }); - cachedPieces = null; // save memory stage = 5; }); ws.on('message', function (data, flags) { - data = encryptor.decrypt(data); - connection.write(data); + connection.write(encryptor.decrypt(data)); }); ws.on('close', function () { diff --git a/server.js b/server.js index 7f78c257..65abb375 100644 --- a/server.js +++ b/server.js @@ -120,7 +120,7 @@ wss.on('connection', function (ws) { remote = net.connect(remotePort, remoteAddr, function () { console.log('connecting', remoteAddr); remote.write(Buffer.concat(cachedPieces)); - cachedPieces = null; // save memory + cachedPieces = null; stage = 5; }); remote.on('data', function (data) { From 855c773d346e4471623c9922047d9188247aee88 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Sun, 10 Mar 2024 00:59:59 +0800 Subject: [PATCH 72/76] Buffer.slice -> Buffer.subarray. --- encrypt.js | 12 ++++++------ local.js | 14 +++++++------- server.js | 6 +++--- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/encrypt.js b/encrypt.js index 6c79be6a..24712b6b 100644 --- a/encrypt.js +++ b/encrypt.js @@ -18,8 +18,8 @@ const EVP_BytesToKey = memoize(function (password, key_len, iv_len) { i += 1; } const ms = Buffer.concat(m); - const key = ms.slice(0, key_len); - const iv = ms.slice(key_len, key_len + iv_len); + const key = ms.subarray(0, key_len); + const iv = ms.subarray(key_len, key_len + iv_len); return [key, iv]; }); @@ -60,9 +60,9 @@ export class Encryptor { iv = iv_; } if (op === 1) { - this.cipher_iv = iv.slice(0, m[1]); + this.cipher_iv = iv.subarray(0, m[1]); } - iv = iv.slice(0, m[1]); + iv = iv.subarray(0, m[1]); if (op === 1) { return crypto.createCipheriv(method, key, iv); } else { @@ -84,9 +84,9 @@ export class Encryptor { decrypt(buf) { if (!this.decipher) { const decipher_iv_len = this.get_cipher_len(this.method)[1]; - const decipher_iv = buf.slice(0, decipher_iv_len); + const decipher_iv = buf.subarray(0, decipher_iv_len); this.decipher = this.get_cipher(this.key, this.method, 0, decipher_iv); - return this.decipher.update(buf.slice(decipher_iv_len)); + return this.decipher.update(buf.subarray(decipher_iv_len)); } else { return this.decipher.update(buf); } diff --git a/local.js b/local.js index 9332d0b8..b23f779a 100644 --- a/local.js +++ b/local.js @@ -136,7 +136,7 @@ var server = net.createServer(function (connection) { connection.end(); return; } - addrToSend = data.slice(3, 4).toString('binary'); + addrToSend = data.subarray(3, 4).toString('binary'); // read address and port if (addrtype === 1) { @@ -146,8 +146,8 @@ var server = net.createServer(function (connection) { connection.end(); return; } - remoteAddr = inetNtoa(4, data.slice(4, 8)); - addrToSend += data.slice(4, 10).toString('binary'); + remoteAddr = inetNtoa(4, data.subarray(4, 8)); + addrToSend += data.subarray(4, 10).toString('binary'); remotePort = data.readUInt16BE(8); } else if (addrtype === 4) { // ipv6 @@ -156,8 +156,8 @@ var server = net.createServer(function (connection) { connection.end(); return; } - remoteAddr = inetNtoa(6, data.slice(4, 20)); - addrToSend += data.slice(4, 22).toString('binary'); + remoteAddr = inetNtoa(6, data.subarray(4, 20)); + addrToSend += data.subarray(4, 22).toString('binary'); remotePort = data.readUInt16BE(20); } else { const addrLen = data[4]; @@ -166,8 +166,8 @@ var server = net.createServer(function (connection) { connection.end(); return; } - remoteAddr = data.slice(5, 5 + addrLen).toString('binary'); - addrToSend += data.slice(4, 5 + addrLen + 2).toString('binary'); + remoteAddr = data.subarray(5, 5 + addrLen).toString('binary'); + addrToSend += data.subarray(4, 5 + addrLen + 2).toString('binary'); remotePort = data.readUInt16BE(5 + addrLen); } let buf = Buffer.alloc(10); diff --git a/server.js b/server.js index 65abb375..ede36bec 100644 --- a/server.js +++ b/server.js @@ -94,7 +94,7 @@ wss.on('connection', function (ws) { ws.close(); return; } - remoteAddr = inetNtoa(4, data.slice(1, 5)); + remoteAddr = inetNtoa(4, data.subarray(1, 5)); remotePort = data.readUInt16BE(5); } else if (addrtype === 4) { // ipv6 @@ -103,7 +103,7 @@ wss.on('connection', function (ws) { ws.close(); return; } - remoteAddr = inetNtoa(6, data.slice(1, 17)); + remoteAddr = inetNtoa(6, data.subarray(1, 17)); remotePort = data.readUInt16BE(17); } else { let addrLen = data[1]; @@ -112,7 +112,7 @@ wss.on('connection', function (ws) { ws.close(); return; } - remoteAddr = data.slice(2, 2 + addrLen).toString('binary'); + remoteAddr = data.subarray(2, 2 + addrLen).toString('binary'); remotePort = data.readUInt16BE(2 + addrLen); } From c6f484c1323c085a70b01d15ff35d47f8a0bf1e3 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Sun, 10 Mar 2024 13:52:50 +0800 Subject: [PATCH 73/76] Simplify IPv6 inetNtoa. --- utils.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/utils.js b/utils.js index 82e40602..24defdf5 100644 --- a/utils.js +++ b/utils.js @@ -1,12 +1,11 @@ export function inetNtoa(family, buf) { if (family === 4) return buf[0] + '.' + buf[1] + '.' + buf[2] + '.' + buf[3]; else if (family === 6) { - let str = Buffer.alloc(0); + let addr = []; for (let i = 0; i < 8; i++) { - str += buf.readUInt16BE(i * 2, i * 2 + 2).toString(16); - if (i < 7) str += ':'; + addr.push(buf.readUInt16BE(i * 2, i * 2 + 2).toString(16)); } - return str; + return addr.join(':'); } } From 6c25c9f6ed3e236fbceee8fe228d574d26b357aa Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Sun, 10 Mar 2024 16:57:48 +0800 Subject: [PATCH 74/76] Run prettier using devenv Pre-Commit Hooks. --- .prettierrc | 2 +- README.md | 9 +++------ devenv.nix | 3 +++ 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.prettierrc b/.prettierrc index f8011d0b..7f5dba43 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,4 +1,4 @@ { "bracketSpacing": false, "singleQuote": true -} \ No newline at end of file +} diff --git a/README.md b/README.md index 0c30e7c5..db52111e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -shadowsocks-heroku -================== +# shadowsocks-heroku shadowsocks-heroku is a lightweight tunnel proxy which can help you get through firewalls. It is a port of [shadowsocks](https://github.com/clowwindy/shadowsocks), but through a different protocol. @@ -7,8 +6,7 @@ shadowsocks-heroku uses WebSocket instead of raw sockets, so it can be deployed Notice that the protocol is INCOMPATIBLE with shadowsocks. -Heroku ------- +## Heroku ### Usage @@ -68,8 +66,7 @@ If there is something wrong, you can check the logs by: $ heroku logs -t --app still-tor-8707 ``` -Supported Ciphers ------------------ +## Supported Ciphers - aes-128-cfb - aes-192-cfb diff --git a/devenv.nix b/devenv.nix index 9e9a429f..269cbab6 100644 --- a/devenv.nix +++ b/devenv.nix @@ -3,4 +3,7 @@ { languages.javascript.enable = true; languages.javascript.package = pkgs.bun; + pre-commit.hooks = { + prettier.enable = true; + }; } From 45ea2a77e21d3cda502483cea398cac84d0824fd Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Sun, 10 Mar 2024 18:22:05 +0800 Subject: [PATCH 75/76] Minor --- encrypt.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/encrypt.js b/encrypt.js index 24712b6b..4218f4f5 100644 --- a/encrypt.js +++ b/encrypt.js @@ -55,10 +55,7 @@ export class Encryptor { password = Buffer.from(password, 'binary'); const m = this.get_cipher_len(method); if (m) { - const [key, iv_] = EVP_BytesToKey(password, m[0], m[1]); - if (!iv) { - iv = iv_; - } + const [key] = EVP_BytesToKey(password, m[0], m[1]); if (op === 1) { this.cipher_iv = iv.subarray(0, m[1]); } From ac4f8f247931e1b14ae0e5ced69f1970f5bd8715 Mon Sep 17 00:00:00 2001 From: Zhao Xiaohong Date: Sun, 10 Mar 2024 17:49:12 +0800 Subject: [PATCH 76/76] GitHub Actions --- .devcontainer.json | 12 ++++++++ .github/workflows/test.yml | 27 +++++++++++++++++ .prettierignore | 3 ++ bun.lockb | Bin 4334 -> 4334 bytes devenv.lock | 12 ++++---- devenv.nix | 11 +++++-- yarn.lock | 58 +++++++++++++++++++++++++++++++++++++ 7 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 .devcontainer.json create mode 100644 .github/workflows/test.yml create mode 100644 .prettierignore create mode 100644 yarn.lock diff --git a/.devcontainer.json b/.devcontainer.json new file mode 100644 index 00000000..75b8759c --- /dev/null +++ b/.devcontainer.json @@ -0,0 +1,12 @@ +{ + "customizations": { + "vscode": { + "extensions": [ + "mkhl.direnv" + ] + } + }, + "image": "ghcr.io/cachix/devenv:latest", + "overrideCommand": false, + "updateContentCommand": "devenv ci" +} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..e407d29c --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,27 @@ +name: 'Test' + +on: + pull_request: + push: + +jobs: + tests: + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + + steps: + - uses: actions/checkout@v4 + - uses: cachix/install-nix-action@v26 + - uses: cachix/cachix-action@v14 + with: + name: devenv + - name: Install devenv.sh + run: nix profile install --accept-flake-config tarball+https://install.devenv.sh/latest + + - name: Build the devenv shell and run any pre-commit hooks + run: devenv ci + + - name: Run a single command in the devenv shell + run: devenv shell bun run test.js diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..4e897cb9 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +*.yml +*.yaml +.devcontainer.json \ No newline at end of file diff --git a/bun.lockb b/bun.lockb index 40eb076f113a67c857f944764f740c1446b2101c..05f25037326c10b3051e1ff484786c3e55d9603e 100755 GIT binary patch delta 20 bcmaE-_)c-dN^W+>IAc8{J=4t_xb0X0P>TkT delta 20 YcmaE-_)c-dN^W*01~AyXf!mH107T&hJpcdz diff --git a/devenv.lock b/devenv.lock index 2fde9653..9c82db41 100644 --- a/devenv.lock +++ b/devenv.lock @@ -3,11 +3,11 @@ "devenv": { "locked": { "dir": "src/modules", - "lastModified": 1709300857, - "narHash": "sha256-jkK99RiSt5YfLWj3kAQoB8OB3idxLTdT9kfo/wILbjw=", + "lastModified": 1709964002, + "narHash": "sha256-uFYF67deIS6RPMzI7e+E+5QtlMZbrk+wYKz9GiTZOac=", "owner": "cachix", "repo": "devenv", - "rev": "f0319af4f966fb8bc25c6429f4f2e097e79116c2", + "rev": "be7e8358c1d871021e3d24acc67e2beb41830e10", "type": "github" }, "original": { @@ -74,11 +74,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1709386671, - "narHash": "sha256-VPqfBnIJ+cfa78pd4Y5Cr6sOWVW8GYHRVucxJGmRf8Q=", + "lastModified": 1710036095, + "narHash": "sha256-joYx0arQtHM/7VhUY5ByP+jlf8XeJkK2fBdri8vK918=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "fa9a51752f1b5de583ad5213eb621be071806663", + "rev": "f592a7ea771bc3c417f7e3026af615d0c6be84ce", "type": "github" }, "original": { diff --git a/devenv.nix b/devenv.nix index 269cbab6..916bd4ef 100644 --- a/devenv.nix +++ b/devenv.nix @@ -1,8 +1,15 @@ { pkgs, ... }: { - languages.javascript.enable = true; - languages.javascript.package = pkgs.bun; + languages.javascript = { + enable = true; + bun = { + enable = true; + install.enable = true; + }; + }; + devcontainer.enable = true; + difftastic.enable = true; pre-commit.hooks = { prettier.enable = true; }; diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..6dd95dc5 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,58 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 +# bun ./bun.lockb --hash: E3146EB5D1A7B6E0-9e360d3d2def5fac-22F8EAE3B40BE372-8d61ebf8f267f773 + + +agent-base@^7.0.2: + version "7.1.0" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz" + integrity sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg== + dependencies: + debug "^4.3.4" + +bufferutil@^4.0.1: + version "4.0.8" + resolved "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz" + integrity sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw== + dependencies: + node-gyp-build "^4.3.0" + +debug@4, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +https-proxy-agent@^7.0.4: + version "7.0.4" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz" + integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg== + dependencies: + agent-base "^7.0.2" + debug "4" + +minimist@^1.2.0: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +node-gyp-build@^4.3.0: + version "4.8.0" + resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz" + integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== + +prettier@^3.2.5: + version "3.2.5" + resolved "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz" + integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== + +ws@^8.16.0: + version "8.16.0" + resolved "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz" + integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==