├── .dockerignore ├── .env ├── .gitignore ├── Dockerfile ├── README.md ├── app.js ├── docker-compose.yml ├── package-lock.json ├── package.json └── supervisord.conf /.dockerignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Dependency directories 12 | node_modules 13 | 14 | # Optional npm cache directory 15 | .npm 16 | 17 | # Application environment 18 | 19 | 20 | # Stored port data 21 | ports.json 22 | 23 | # ssl certificate and key 24 | ca.cert 25 | ca.key 26 | ca.srl 27 | server.cert 28 | server.key 29 | server.csr 30 | 31 | 32 | 33 | Dockerfile 34 | LICENSE 35 | README.md 36 | .gitignore 37 | .dockerignore 38 | docker-compose.yml -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | LOGIN_PASSWORD = changeThisSecret-long-long-pa$$word!@#123!@# 2 | LISTEN_PORT = 4001 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Dependency directories 12 | node_modules 13 | 14 | # Optional npm cache directory 15 | .npm 16 | 17 | # Stored port data 18 | ports.json 19 | 20 | # ssl certificate and key 21 | ca.cert 22 | ca.key 23 | ca.srl 24 | server.cert 25 | server.key 26 | server.csr -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | WORKDIR /shadowsocks-restful-api 4 | 5 | COPY . . 6 | 7 | RUN apt-get update && apt-get install -y curl python-dev make g++ software-properties-common supervisor 8 | 9 | RUN set -ex && \ 10 | add-apt-repository ppa:max-c-lv/shadowsocks-libev -y && \ 11 | curl -sL https://deb.nodesource.com/setup_8.x | bash - && \ 12 | apt-get update && apt-get install nodejs shadowsocks-libev -y && \ 13 | npm i && \ 14 | mkdir -p /var/log/supervisor && \ 15 | cp supervisord.conf /etc/supervisor/conf.d/supervisord.conf && \ 16 | rm supervisord.conf && \ 17 | openssl req -x509 -sha256 -nodes -days 3365 \ 18 | -subj "/C=CA/ST=QC/O=Company Inc/CN=example.com" \ 19 | -newkey rsa:2048 -keyout server.key \ 20 | -out server.cert 21 | 22 | 23 | RUN apt-get purge -y curl git software-properties-common && apt-get clean -y && apt-get autoclean -y && apt-get autoremove -y && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 24 | 25 | 26 | CMD ["/usr/bin/supervisord"] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shadowsocks Restful Api 2 | A secure, reliable, standard restful api for managing shadowsocks-libev. 3 | 4 | A web app that manages users, server, nodes, products, accounts, and traffic can be found from [shadowsocks-hub](https://github.com/shadowsocks/shadowsocks-hub). 5 | 6 | ## Install with Docker 7 | 8 | #### Install Docker and Compose plugin: 9 | ``` 10 | curl -fsSL https://get.docker.com -o get-docker.sh 11 | DRY_RUN=1 sudo sh ./get-docker.sh 12 | ``` 13 | 14 | #### Download shadowsocks-restful-api: 15 | ``` 16 | cd ~ 17 | git clone https://github.com/shadowsocks/shadowsocks-restful-api.git 18 | ``` 19 | 20 | #### Change the login password of REST-api: 21 | ``` 22 | cd shadowsocks-restful-api/ 23 | nano .env 24 | ``` 25 | * Note: LOGIN_PASSWORD in .env file, should be long and complex 26 | 27 | #### Build and run: 28 | ``` 29 | docker build -t shadow-rest:1.0.0 . 30 | docker compose up -d 31 | ``` 32 | 33 | #### Test it with LOGIN_PASSWORD to get jwt token: 34 | ``` 35 | curl -ik -H "Content-Type: application/json" -X POST -d '{"password":"changeThisSecret-long-long-pa$$word!@#123!@#"}' https://:4001/login 36 | ``` 37 | Response example: 38 | ```json 39 | {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1Mjk0ODg0MTcsImV4cCI6MTUyOTU3NDgxN30.9wdDV4hXvHdCkWhcOFpW2YXvSL6WupWSj2kTI6XMhFk"} 40 | ``` 41 | 42 | ## Install (Ubuntu 16.04) 43 | 44 | #### Download shadowsocks-restful-api: 45 | ``` 46 | cd ~ 47 | git clone https://github.com/shadowsocks/shadowsocks-restful-api.git 48 | ``` 49 | 50 | #### Install Node: 51 | ``` 52 | curl -sL https://deb.nodesource.com/setup_8.x | sudo bash - 53 | sudo apt-get install nodejs -y 54 | ``` 55 | 56 | #### Install dependencies: 57 | ``` 58 | sudo apt-get install -y python-dev make g++ screen 59 | cd ~/shadowsocks-restful-api 60 | npm i 61 | ``` 62 | 63 | #### Install shadowsocks-libev: 64 | ``` 65 | sudo apt-get install software-properties-common -y 66 | sudo add-apt-repository ppa:max-c-lv/shadowsocks-libev -y 67 | sudo apt-get update 68 | sudo apt install shadowsocks-libev 69 | ``` 70 | 71 | #### Create digital certificate: 72 | ``` 73 | cd ~/shadowsocks-restful-api 74 | openssl req -nodes -x509 -newkey rsa:4096 -keyout server.key -out server.cert -days 365 75 | ``` 76 | 77 | #### Create config file: 78 | ``` 79 | cd ~/shadowsocks-restful-api 80 | touch .env 81 | echo 'LOGIN_PASSWORD = pleaseChangeThisPassword' >> .env 82 | echo 'LISTEN_PORT = 4001' >> .env 83 | ``` 84 | 85 | ## Run 86 | 87 | #### Run shadowsocks-libev in the background: 88 | ``` 89 | screen -dm ss-manager -u --manager-address /tmp/shadowsocks-manager.sock --fast-open 90 | ``` 91 | 92 | #### Run shadowsocks-restful-api in the background: 93 | ``` 94 | cd ~/shadowsocks-restful-api 95 | screen -dm node app.js 96 | ``` 97 | 98 | ## API 99 | 100 | #### Login 101 | | | | 102 | | :---------------------------- | :---------------------------------------------------------------- | 103 | | Request method: | POST | 104 | | Request URL: | https://host_name:port/login | 105 | | Request Header: | Content-Type: application/json | 106 | | Request Body: | {"password": "your_login_password"} | 107 | | Response HTTP Status Code: | 201 Created | 108 | | Response Body: | {"token","your_authentication_token"} | 109 | | Response Error Status Code: | 401 Unauthorized
500 Internal Server Error | 110 | 111 | Request example (curl): 112 | ``` 113 | curl -ik -H "Content-Type: application/json" -X POST -d '{"password":"pleaseChangeThisPassword"}' https://localhost:4001/login 114 | ``` 115 | Response example: 116 | ```json 117 | {"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1Mjk0ODg0MTcsImV4cCI6MTUyOTU3NDgxN30.9wdDV4hXvHdCkWhcOFpW2YXvSL6WupWSj2kTI6XMhFk"} 118 | ``` 119 | 120 | #### Ping 121 | | | | 122 | | :---------------------------- | :---------------------------------------------------------------- | 123 | | Request method: | GET | 124 | | Request URL: | https://host_name:port/ping | 125 | | Request Header: | Authorization: Bearer your_authentication_toke | 126 | | Response HTTP Status Code: | 200 OK | 127 | | Response Body: | {"pong":"pong"} | 128 | | Response Error Status Code: | 401 Unauthorized
424 (shadowsocks unreachable)
425 (shadowsocks no response)
500 Internal Server Error | 129 | 130 | Request example (curl): 131 | ``` 132 | curl -ik -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1Mjk0ODg0MTcsImV4cCI6MTUyOTU3NDgxN30.9wdDV4hXvHdCkWhcOFpW2YXvSL6WupWSj2kTI6XMhFk" https://localhost:4001/ping 133 | ``` 134 | Response example: 135 | ```json 136 | {"pong":"pong"} 137 | ``` 138 | 139 | #### Add a port 140 | | | | 141 | | :---------------------------- | :---------------------------------------------------------------- | 142 | | Request method: | POST | 143 | | Request URL: | https://host_name:port/ | 144 | | Request Header: | Content-Type: application/json
Authorization: Bearer your_authentication_toke | 145 | | Request Body: | {"port": port_number, "password": "port_password", "method": "encryption_method"} | 146 | | Response HTTP Status Code: | 201 Created | 147 | | Response Error Status Code: | 401 Unauthorized
409 (port already exists from shadowsocks)
410 (port not available from operating system)
422 (shadowsocks failed adding port)
427 (operating system failed adding port) 424 (shadowsocks unreachable)
425 (shadowsocks no response)
500 Internal Server Error | 148 | 149 | Request example (curl): 150 | ``` 151 | curl -ik -H "Content-Type: application/json" -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1Mjk0ODg0MTcsImV4cCI6MTUyOTU3NDgxN30.9wdDV4hXvHdCkWhcOFpW2YXvSL6WupWSj2kTI6XMhFk" -X POST -d '{"port": 50000,"password":"2owkq9wu2elwst7","method":"chacha20-ietf-poly1305"}' https://localhost:4001/ 152 | ``` 153 | 154 | Supported encryption methods are: 155 | * `aes-128-gcm` 156 | * `aes-192-gcm` 157 | * `aes-256-gcm` 158 | * `aes-128-cfb` 159 | * `aes-192-cfb` 160 | * `aes-256-cfb` 161 | * `aes-128-ctr` 162 | * `aes-192-ctr` 163 | * `aes-256-ctr` 164 | * `camellia-128-cfb` 165 | * `camellia-192-cfb` 166 | * `camellia-256-cfb` 167 | * `bf-cfb` 168 | * `chacha20-ietf-poly1305` 169 | * `xchacha20-ietf-poly1305` 170 | * `salsa20` 171 | * `chacha20` 172 | * `chacha20-ietf` 173 | 174 | If the `method` field is not supplied, the default method is `aes-256-cfb`. 175 | 176 | #### Delete a port 177 | | | | 178 | | :---------------------------- | :---------------------------------------------------------------- | 179 | | Request method: | DELETE | 180 | | Request URL: | https://host_name:port?port=port_number | 181 | | Request Header: | Authorization: Bearer your_authentication_toke | 182 | | Response HTTP Status Code: | 204 No Content | 183 | | Response Error Status Code: | 401 Unauthorized
422 (shadowsocks failed removing port)
427 (operating system failed removing port)
424 (shadowsocks unreachable)
425 (shadowsocks no response)
500 Internal Server Error | 184 | 185 | Request example (curl): 186 | ``` 187 | curl -ik -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1Mjk0ODg0MTcsImV4cCI6MTUyOTU3NDgxN30.9wdDV4hXvHdCkWhcOFpW2YXvSL6WupWSj2kTI6XMhFk" -X DELETE https://localhost:4001?port=50000 188 | ``` 189 | 190 | #### Get all ports 191 | | | | 192 | | :---------------------------- | :---------------------------------------------------------------- | 193 | | Request method: | GET | 194 | | Request URL: | https://host_name:port/all | 195 | | Request Header: | Authorization: Bearer your_authentication_toke | 196 | | Response HTTP Status Code: | 200 OK | 197 | | Response Body: | [{"port":port_number, "password":"port_password","method":"encryption_method"}, ... ] | 198 | | Response Error Status Code: | 401 Unauthorized
424 (shadowsocks unreachable)
425 (shadowsocks no response)
500 Internal Server Error | 199 | 200 | Request example (curl): 201 | ``` 202 | curl -ik -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1Mjk0ODg0MTcsImV4cCI6MTUyOTU3NDgxN30.9wdDV4hXvHdCkWhcOFpW2YXvSL6WupWSj2kTI6XMhFk" https://localhost:4001/all 203 | ``` 204 | Response example: 205 | ```json 206 | [{"port": 50000,"password":"2owkq9wu2elwst7","method":"chacha20-ietf-poly1305"}, {"port": 50001,"password":"dowl3829j3suniw6","method":"aes-256-cfb"}] 207 | ``` 208 | 209 | #### Get traffic for all ports 210 | | | | 211 | | :---------------------------- | :---------------------------------------------------------------- | 212 | | Request method: | GET | 213 | | Request URL: | https://host_name:port/traffic/all | 214 | | Request Header: | Authorization: Bearer your_authentication_toke | 215 | | Response HTTP Status Code: | 200 OK | 216 | | Response Body: | [{"port":port_number, "traffic": traffic_usage}, ... ] | 217 | | Response Error Status Code: | 401 Unauthorized
424 (shadowsocks unreachable)
425 (shadowsocks no response)
500 Internal Server Error | 218 | 219 | Request example (curl): 220 | ``` 221 | curl -ik -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1Mjk0ODg0MTcsImV4cCI6MTUyOTU3NDgxN30.9wdDV4hXvHdCkWhcOFpW2YXvSL6WupWSj2kTI6XMhFk" https://localhost:4001/traffic/all 222 | ``` 223 | Response example: 224 | ```json 225 | [{"port": 50000,"traffic":928727287}, {"port": 50001,"traffic":0}] 226 | ``` 227 | 228 | ## Authentication 229 | 230 | All the api requests except for login require an Authorization header. The header pattern is: `Authorization: Bearer `. The token can be obtained from the login api. 231 | 232 | A token expires in 24 hours. A new token is needed once the old one expires. Tokens can be re-used in multiple requests before exiration. 233 | 234 | ## Security 235 | 236 | This program encrypts all the traffic end-to-end using https. It requires you to set up a digital certificate. There are many ways that you can get a free digital certificate. You may also generate your own self-signed digital certificate: 237 | 238 | ``` 239 | cd ~/shadowsocks-restful-api/ 240 | openssl req -nodes -x509 -newkey rsa:4096 -keyout server.key -out server.cert -days 365 241 | ``` 242 | 243 | ## Reliability 244 | 245 | This program aims to achieve best reliability. It will attempt to re-open the ports upon restart of shadowsocks or this program itself. It also keeps monitoring the opened ports. Should anyone were dropped (due to any unprecedented reason), this program would attemp to re-open it. 246 | 247 | ## Bug report and feature request 248 | 249 | Welcome to create an issue for them. Bugs have high priority to get addressed. Feature requests will depend on their popularity, importance. 250 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | !function(e) { 2 | var r = {}; 3 | function t(n) { 4 | if (r[n]) return r[n].exports; 5 | var a = r[n] = { 6 | i: n, 7 | l: !1, 8 | exports: {} 9 | }; 10 | return e[n].call(a.exports, a, a.exports, t), a.l = !0, a.exports; 11 | } 12 | t.m = e, t.c = r, t.d = function(e, r, n) { 13 | t.o(e, r) || Object.defineProperty(e, r, { 14 | enumerable: !0, 15 | get: n 16 | }); 17 | }, t.r = function(e) { 18 | "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(e, Symbol.toStringTag, { 19 | value: "Module" 20 | }), Object.defineProperty(e, "__esModule", { 21 | value: !0 22 | }); 23 | }, t.t = function(e, r) { 24 | if (1 & r && (e = t(e)), 8 & r) return e; 25 | if (4 & r && "object" == typeof e && e && e.__esModule) return e; 26 | var n = Object.create(null); 27 | if (t.r(n), Object.defineProperty(n, "default", { 28 | enumerable: !0, 29 | value: e 30 | }), 2 & r && "string" != typeof e) for (var a in e) t.d(n, a, function(r) { 31 | return e[r]; 32 | }.bind(null, a)); 33 | return n; 34 | }, t.n = function(e) { 35 | var r = e && e.__esModule ? function() { 36 | return e.default; 37 | } : function() { 38 | return e; 39 | }; 40 | return t.d(r, "a", r), r; 41 | }, t.o = function(e, r) { 42 | return Object.prototype.hasOwnProperty.call(e, r); 43 | }, t.p = "", t(t.s = 21); 44 | }([ function(e, r) { 45 | e.exports = require("debug"); 46 | }, function(e, r) { 47 | e.exports = require("validator"); 48 | }, function(e, r) { 49 | e.exports = require("fs"); 50 | }, function(e, r) { 51 | e.exports = require("path"); 52 | }, function(e, r) { 53 | e.exports = require("crypto"); 54 | }, function(e, r) { 55 | e.exports = require("jsonwebtoken"); 56 | }, function(e, r, t) { 57 | "use strict"; 58 | var n, a, s, o = (n = u(regeneratorRuntime.mark(function e(r) { 59 | var t, n, a; 60 | return regeneratorRuntime.wrap(function(e) { 61 | for (;;) switch (e.prev = e.next) { 62 | case 0: 63 | if (r) { 64 | e.next = 2; 65 | break; 66 | } 67 | throw new Error("illegal argument"); 68 | 69 | case 2: 70 | if (t = r.port, n = r.password, a = r.method, !(!t || !Number.isInteger(t) || t < 1 || t > 65535)) { 71 | e.next = 6; 72 | break; 73 | } 74 | throw new Error("illegal argument"); 75 | 76 | case 6: 77 | if (n && "string" == typeof n && !(n.length < 1)) { 78 | e.next = 9; 79 | break; 80 | } 81 | throw new Error("illegal argument"); 82 | 83 | case 9: 84 | if (a && "string" == typeof a && l.isIn(a, [ "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "bf-cfb", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "salsa20", "chacha20", "chacha20-ietf" ])) { 85 | e.next = 12; 86 | break; 87 | } 88 | throw new Error("illegal argument"); 89 | 90 | case 12: 91 | m.addPort({ 92 | port: t, 93 | password: n, 94 | method: a 95 | }); 96 | 97 | case 14: 98 | case "end": 99 | return e.stop(); 100 | } 101 | }, e, this); 102 | })), function(e) { 103 | return n.apply(this, arguments); 104 | }), i = (a = u(regeneratorRuntime.mark(function e(r) { 105 | return regeneratorRuntime.wrap(function(e) { 106 | for (;;) switch (e.prev = e.next) { 107 | case 0: 108 | if (!(isNaN(r) || !Number.isInteger(r) || r < 1 || r > 65535)) { 109 | e.next = 2; 110 | break; 111 | } 112 | throw new Error("illegal argument"); 113 | 114 | case 2: 115 | return e.next = 5, m.removePort(r); 116 | 117 | case 5: 118 | case "end": 119 | return e.stop(); 120 | } 121 | }, e, this); 122 | })), function(e) { 123 | return a.apply(this, arguments); 124 | }), c = (s = u(regeneratorRuntime.mark(function e() { 125 | var r; 126 | return regeneratorRuntime.wrap(function(e) { 127 | for (;;) switch (e.prev = e.next) { 128 | case 0: 129 | return r = m.getPorts(), e.abrupt("return", r); 130 | 131 | case 2: 132 | case "end": 133 | return e.stop(); 134 | } 135 | }, e, this); 136 | })), function() { 137 | return s.apply(this, arguments); 138 | }); 139 | function u(e) { 140 | return function() { 141 | var r = e.apply(this, arguments); 142 | return new Promise(function(e, t) { 143 | return function n(a, s) { 144 | try { 145 | var o = r[a](s), i = o.value; 146 | } catch (e) { 147 | return void t(e); 148 | } 149 | if (!o.done) return Promise.resolve(i).then(function(e) { 150 | n("next", e); 151 | }, function(e) { 152 | n("throw", e); 153 | }); 154 | e(i); 155 | }("next"); 156 | }); 157 | }; 158 | } 159 | var p = t(2), f = t(3), l = t(1), h = (t(0)("dao"), f.resolve(__dirname, "./ports.json")), m = { 160 | ports: [], 161 | getPorts: function() { 162 | return this.ports; 163 | }, 164 | setPorts: function(e) { 165 | if (!e || !Array.isArray(e)) throw new Error("illegal argument"); 166 | e.forEach(function(e) { 167 | var r = e.port, t = e.password, n = e.method; 168 | if (!r || !Number.isInteger(r) || r < 1 || r > 65535) throw new Error("illegal argument, port illegal"); 169 | if (!t || "string" != typeof t || t.length < 1) throw new Error("illegal argument, password illegal"); 170 | if (!n || "string" != typeof n || !l.isIn(n, [ "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "bf-cfb", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "salsa20", "chacha20", "chacha20-ietf" ])) throw new Error("illegal argument"); 171 | }); 172 | var r = e.map(function(e) { 173 | return e.port; 174 | }); 175 | if (new Set(r).size !== r.length) throw new Error("illegal argument, duplicate ports"); 176 | this.ports = JSON.parse(JSON.stringify(e)); 177 | }, 178 | addPort: function(e) { 179 | if (!e) throw new Error("illegal argument"); 180 | var r = e.port, t = e.password, n = e.method; 181 | if (!r || !Number.isInteger(r) || r < 1 || r > 65535) throw new Error("illegal argument"); 182 | if (!t || "string" != typeof t || t.length < 1) throw new Error("illegal argument"); 183 | if (!n || "string" != typeof n || !l.isIn(n, [ "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "bf-cfb", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "salsa20", "chacha20", "chacha20-ietf" ])) throw new Error("illegal argument"); 184 | if (this.ports.map(function(e) { 185 | return e.port; 186 | }).includes(r)) throw new Error("port already exists in database"); 187 | this.ports.push({ 188 | port: r, 189 | password: t, 190 | method: n 191 | }), this.savePortsToFile(); 192 | }, 193 | removePort: function(e) { 194 | if (isNaN(e) || !Number.isInteger(e) || e < 1 || e > 65535) throw new Error("illegal argument"); 195 | this.ports = this.ports.filter(function(r) { 196 | return r.port !== e; 197 | }), this.savePortsToFile(); 198 | }, 199 | initPortsFromFile: function() { 200 | try { 201 | var e = p.readFileSync(h, "utf8"); 202 | e && this.setPorts(JSON.parse(e)); 203 | } catch (e) { 204 | p.openSync(h, "w"); 205 | } 206 | }, 207 | savePortsToFile: function() { 208 | p.writeFile(h, JSON.stringify(this.ports), function(e) { 209 | if (e) throw e; 210 | }); 211 | } 212 | }; 213 | m.initPortsFromFile(), e.exports.addPort = o, e.exports.removePort = i, e.exports.getAllPorts = c; 214 | }, function(e, r) { 215 | e.exports = require("portastic"); 216 | }, function(e, r) { 217 | e.exports = require("async-lock"); 218 | }, function(e, r) { 219 | e.exports = require("unix-dgram"); 220 | }, function(e, r, t) { 221 | "use strict"; 222 | var n, a, s, o, i, c, u, p, f, l, h, m, g, d, w, b, x, v, y = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(e) { 223 | return typeof e; 224 | } : function(e) { 225 | return e && "function" == typeof Symbol && e.constructor === Symbol && e !== Symbol.prototype ? "symbol" : typeof e; 226 | }, k = (n = W(regeneratorRuntime.mark(function e() { 227 | var r, t, n, a, s = this; 228 | return regeneratorRuntime.wrap(function(e) { 229 | for (;;) switch (e.prev = e.next) { 230 | case 0: 231 | return e.next = 2, U.getAllPorts(); 232 | 233 | case 2: 234 | return r = e.sent, e.prev = 3, e.next = 6, N(); 235 | 236 | case 6: 237 | t = e.sent, n = t.map(function(e) { 238 | return e.port; 239 | }), r.forEach(function() { 240 | var e = W(regeneratorRuntime.mark(function e(r) { 241 | return regeneratorRuntime.wrap(function(e) { 242 | for (;;) switch (e.prev = e.next) { 243 | case 0: 244 | if (n.includes(r.port)) { 245 | e.next = 3; 246 | break; 247 | } 248 | return e.next = 3, P(r); 249 | 250 | case 3: 251 | case 4: 252 | case "end": 253 | return e.stop(); 254 | } 255 | }, e, s); 256 | })); 257 | return function(r) { 258 | return e.apply(this, arguments); 259 | }; 260 | }()), a = r.map(function(e) { 261 | return e.port; 262 | }), t.forEach(function() { 263 | var e = W(regeneratorRuntime.mark(function e(r) { 264 | return regeneratorRuntime.wrap(function(e) { 265 | for (;;) switch (e.prev = e.next) { 266 | case 0: 267 | if (a.includes(r.port)) { 268 | e.next = 3; 269 | break; 270 | } 271 | return e.next = 3, O(r.port); 272 | 273 | case 3: 274 | case 4: 275 | case "end": 276 | return e.stop(); 277 | } 278 | }, e, s); 279 | })); 280 | return function(r) { 281 | return e.apply(this, arguments); 282 | }; 283 | }()), e.next = 23; 284 | break; 285 | 286 | case 13: 287 | if (e.prev = 13, e.t0 = e.catch(3), "shadowsocks unreachable" !== e.t0.message) { 288 | e.next = 18; 289 | break; 290 | } 291 | e.next = 22; 292 | break; 293 | 294 | case 18: 295 | if ("shadowsocks no response" !== e.t0.message) { 296 | e.next = 21; 297 | break; 298 | } 299 | e.next = 22; 300 | break; 301 | 302 | case 21: 303 | throw e.t0; 304 | 305 | case 22: 306 | case 23: 307 | case 24: 308 | case "end": 309 | return e.stop(); 310 | } 311 | }, e, this, [ [ 3, 13 ] ]); 312 | })), function() { 313 | return n.apply(this, arguments); 314 | }), E = (a = W(regeneratorRuntime.mark(function e(r) { 315 | return regeneratorRuntime.wrap(function(e) { 316 | for (;;) switch (e.prev = e.next) { 317 | case 0: 318 | if (r) { 319 | e.next = 2; 320 | break; 321 | } 322 | throw new Error("illegal argument"); 323 | 324 | case 2: 325 | if (r === Y) { 326 | e.next = 5; 327 | break; 328 | } 329 | throw new Error("invalid password"); 330 | 331 | case 5: 332 | case 6: 333 | case "end": 334 | return e.stop(); 335 | } 336 | }, e, this); 337 | })), function(e) { 338 | return a.apply(this, arguments); 339 | }), R = (s = W(regeneratorRuntime.mark(function e(r) { 340 | var t, n, a; 341 | return regeneratorRuntime.wrap(function(e) { 342 | for (;;) switch (e.prev = e.next) { 343 | case 0: 344 | if (r) { 345 | e.next = 2; 346 | break; 347 | } 348 | throw new Error("illegal argument"); 349 | 350 | case 2: 351 | if (t = r.port, n = r.password, a = r.method, !(!t || !Number.isInteger(t) || t < 1 || t > 65535)) { 352 | e.next = 6; 353 | break; 354 | } 355 | throw new Error("illegal argument"); 356 | 357 | case 6: 358 | if (n && "string" == typeof n && !(n.length < 1)) { 359 | e.next = 9; 360 | break; 361 | } 362 | throw new Error("illegal argument"); 363 | 364 | case 9: 365 | if (a && "string" == typeof a && H.isIn(a, [ "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "bf-cfb", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "salsa20", "chacha20", "chacha20-ietf" ])) { 366 | e.next = 12; 367 | break; 368 | } 369 | throw new Error("illegal argument"); 370 | 371 | case 12: 372 | return e.next = 15, P({ 373 | port: t, 374 | password: n, 375 | method: a 376 | }); 377 | 378 | case 15: 379 | return e.next = 17, U.addPort({ 380 | port: t, 381 | password: n, 382 | method: a 383 | }); 384 | 385 | case 17: 386 | case "end": 387 | return e.stop(); 388 | } 389 | }, e, this); 390 | })), function(e) { 391 | return s.apply(this, arguments); 392 | }), P = (o = W(regeneratorRuntime.mark(function e(r) { 393 | var t, n, a, s; 394 | return regeneratorRuntime.wrap(function(e) { 395 | for (;;) switch (e.prev = e.next) { 396 | case 0: 397 | if (r) { 398 | e.next = 2; 399 | break; 400 | } 401 | throw new Error("illegal argument"); 402 | 403 | case 2: 404 | if (t = r.port, n = r.password, a = r.method, !(!t || !Number.isInteger(t) || t < 1 || t > 65535)) { 405 | e.next = 6; 406 | break; 407 | } 408 | throw new Error("illegal argument"); 409 | 410 | case 6: 411 | if (n && "string" == typeof n && !(n.length < 1)) { 412 | e.next = 9; 413 | break; 414 | } 415 | throw new Error("illegal argument"); 416 | 417 | case 9: 418 | if (a && "string" == typeof a && H.isIn(a, [ "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "bf-cfb", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "salsa20", "chacha20", "chacha20-ietf" ])) { 419 | e.next = 12; 420 | break; 421 | } 422 | throw new Error("illegal argument"); 423 | 424 | case 12: 425 | return e.next = 15, J(t); 426 | 427 | case 15: 428 | if (!e.sent) { 429 | e.next = 17; 430 | break; 431 | } 432 | throw new Error("port already exists from shadowsocks"); 433 | 434 | case 17: 435 | return e.next = 20, L(t); 436 | 437 | case 20: 438 | if (e.sent) { 439 | e.next = 22; 440 | break; 441 | } 442 | throw new Error("port not available from operating system"); 443 | 444 | case 22: 445 | return e.next = 25, Z.getType(); 446 | 447 | case 25: 448 | if ("libev" !== (s = e.sent)) { 449 | e.next = 31; 450 | break; 451 | } 452 | return e.next = 29, j({ 453 | port: t, 454 | password: n, 455 | method: a 456 | }); 457 | 458 | case 29: 459 | e.next = 37; 460 | break; 461 | 462 | case 31: 463 | if ("python" !== s) { 464 | e.next = 36; 465 | break; 466 | } 467 | return e.next = 34, F({ 468 | port: t, 469 | password: n 470 | }); 471 | 472 | case 34: 473 | e.next = 37; 474 | break; 475 | 476 | case 36: 477 | throw new Error("should not come here"); 478 | 479 | case 37: 480 | return e.next = 40, J(t); 481 | 482 | case 40: 483 | if (e.sent) { 484 | e.next = 42; 485 | break; 486 | } 487 | throw new Error("shadowsocks failed adding port"); 488 | 489 | case 42: 490 | case 43: 491 | case "end": 492 | return e.stop(); 493 | } 494 | }, e, this); 495 | })), function(e) { 496 | return o.apply(this, arguments); 497 | }), N = (i = W(regeneratorRuntime.mark(function e() { 498 | var r, t, n; 499 | return regeneratorRuntime.wrap(function(e) { 500 | for (;;) switch (e.prev = e.next) { 501 | case 0: 502 | return e.next = 2, Z.getType(); 503 | 504 | case 2: 505 | if ("libev" !== (r = e.sent)) { 506 | e.next = 10; 507 | break; 508 | } 509 | return e.next = 6, A(); 510 | 511 | case 6: 512 | return t = e.sent, e.abrupt("return", t); 513 | 514 | case 10: 515 | if ("python" !== r) { 516 | e.next = 17; 517 | break; 518 | } 519 | return e.next = 13, getAllPortsFromPython(); 520 | 521 | case 13: 522 | return n = e.sent, e.abrupt("return", n); 523 | 524 | case 17: 525 | throw new Error("should not come here"); 526 | 527 | case 18: 528 | case 19: 529 | case "end": 530 | return e.stop(); 531 | } 532 | }, e, this); 533 | })), function() { 534 | return i.apply(this, arguments); 535 | }), S = (c = W(regeneratorRuntime.mark(function e() { 536 | var r, t, n; 537 | return regeneratorRuntime.wrap(function(e) { 538 | for (;;) switch (e.prev = e.next) { 539 | case 0: 540 | return e.next = 2, Z.getType(); 541 | 542 | case 2: 543 | if ("libev" !== (r = e.sent)) { 544 | e.next = 10; 545 | break; 546 | } 547 | return e.next = 6, q(); 548 | 549 | case 6: 550 | return t = e.sent, e.abrupt("return", t); 551 | 552 | case 10: 553 | if ("python" !== r) { 554 | e.next = 17; 555 | break; 556 | } 557 | return e.next = 13, getAllTrafficFromPython(); 558 | 559 | case 13: 560 | return n = e.sent, e.abrupt("return", n); 561 | 562 | case 17: 563 | throw new Error("should not come here"); 564 | 565 | case 18: 566 | case 19: 567 | case "end": 568 | return e.stop(); 569 | } 570 | }, e, this); 571 | })), function() { 572 | return c.apply(this, arguments); 573 | }), I = (u = W(regeneratorRuntime.mark(function e() { 574 | var r, t; 575 | return regeneratorRuntime.wrap(function(e) { 576 | for (;;) switch (e.prev = e.next) { 577 | case 0: 578 | return e.next = 2, Z.getType(); 579 | 580 | case 2: 581 | if ("libev" !== (r = e.sent)) { 582 | e.next = 8; 583 | break; 584 | } 585 | return e.next = 6, T(); 586 | 587 | case 6: 588 | e.next = 14; 589 | break; 590 | 591 | case 8: 592 | if ("python" !== r) { 593 | e.next = 13; 594 | break; 595 | } 596 | return e.next = 11, _(); 597 | 598 | case 11: 599 | e.next = 14; 600 | break; 601 | 602 | case 13: 603 | throw new Error("should not come here"); 604 | 605 | case 14: 606 | return t = { 607 | pong: "pong" 608 | }, e.abrupt("return", t); 609 | 610 | case 17: 611 | case "end": 612 | return e.stop(); 613 | } 614 | }, e, this); 615 | })), function() { 616 | return u.apply(this, arguments); 617 | }), O = (p = W(regeneratorRuntime.mark(function e(r) { 618 | var t; 619 | return regeneratorRuntime.wrap(function(e) { 620 | for (;;) switch (e.prev = e.next) { 621 | case 0: 622 | if (!(isNaN(r) || !Number.isInteger(r) || r < 1 || r > 65535)) { 623 | e.next = 2; 624 | break; 625 | } 626 | throw new Error("illegal argument"); 627 | 628 | case 2: 629 | return e.next = 5, Z.getType(); 630 | 631 | case 5: 632 | if ("libev" !== (t = e.sent)) { 633 | e.next = 11; 634 | break; 635 | } 636 | return e.next = 9, K(r); 637 | 638 | case 9: 639 | e.next = 17; 640 | break; 641 | 642 | case 11: 643 | if ("python" !== t) { 644 | e.next = 16; 645 | break; 646 | } 647 | return e.next = 14, C(r); 648 | 649 | case 14: 650 | e.next = 17; 651 | break; 652 | 653 | case 16: 654 | throw new Error("should not come here"); 655 | 656 | case 17: 657 | return e.next = 20, J(r); 658 | 659 | case 20: 660 | if (!e.sent) { 661 | e.next = 22; 662 | break; 663 | } 664 | throw new Error("shadowsocks failed removing port"); 665 | 666 | case 22: 667 | return e.next = 25, L(r); 668 | 669 | case 25: 670 | if (e.sent) { 671 | e.next = 27; 672 | break; 673 | } 674 | throw new Error("operating system failed removing port"); 675 | 676 | case 27: 677 | return e.next = 30, U.removePort(r); 678 | 679 | case 30: 680 | case "end": 681 | return e.stop(); 682 | } 683 | }, e, this); 684 | })), function(e) { 685 | return p.apply(this, arguments); 686 | }), T = (f = W(regeneratorRuntime.mark(function e() { 687 | var r, t, n; 688 | return regeneratorRuntime.wrap(function(e) { 689 | for (;;) switch (e.prev = e.next) { 690 | case 0: 691 | return r = $.getCommandKeyword("libev", "ping"), e.next = 3, ee(r); 692 | 693 | case 3: 694 | if ("stat:" !== (t = e.sent).substr(0, 5)) { 695 | e.next = 9; 696 | break; 697 | } 698 | return n = JSON.parse(t.substr(5)), e.abrupt("return", n); 699 | 700 | case 9: 701 | throw new Error("pingLibev, received unknown message"); 702 | 703 | case 10: 704 | case 11: 705 | case "end": 706 | return e.stop(); 707 | } 708 | }, e, this); 709 | })), function() { 710 | return f.apply(this, arguments); 711 | }), _ = (l = W(regeneratorRuntime.mark(function e() { 712 | var r, t; 713 | return regeneratorRuntime.wrap(function(e) { 714 | for (;;) switch (e.prev = e.next) { 715 | case 0: 716 | return r = $.getCommandKeyword("python", "ping"), e.next = 3, ee(r); 717 | 718 | case 3: 719 | if ("pong" !== (t = e.sent).substr(0, 4)) { 720 | e.next = 8; 721 | break; 722 | } 723 | return e.abrupt("return", t); 724 | 725 | case 8: 726 | throw new Error("pingPython, received unknown message"); 727 | 728 | case 9: 729 | case 10: 730 | case "end": 731 | return e.stop(); 732 | } 733 | }, e, this); 734 | })), function() { 735 | return l.apply(this, arguments); 736 | }), A = (h = W(regeneratorRuntime.mark(function e() { 737 | var r, t, n, a; 738 | return regeneratorRuntime.wrap(function(e) { 739 | for (;;) switch (e.prev = e.next) { 740 | case 0: 741 | return r = $.getCommandKeyword("libev", "getAllPorts"), e.next = 3, ee(r); 742 | 743 | case 3: 744 | if (t = e.sent, n = [], "[\n\t" !== t.substr(0, 3)) { 745 | e.next = 10; 746 | break; 747 | } 748 | a = JSON.parse(t), n = a.map(function(e) { 749 | return { 750 | port: Number(e.server_port), 751 | password: e.password, 752 | method: e.method 753 | }; 754 | }), e.next = 14; 755 | break; 756 | 757 | case 10: 758 | if ("\n]" !== t.substr(0, 2)) { 759 | e.next = 13; 760 | break; 761 | } 762 | e.next = 14; 763 | break; 764 | 765 | case 13: 766 | throw new Error("getAllPortsFromLibev, received unknown message"); 767 | 768 | case 14: 769 | return e.abrupt("return", n); 770 | 771 | case 16: 772 | case "end": 773 | return e.stop(); 774 | } 775 | }, e, this); 776 | })), function() { 777 | return h.apply(this, arguments); 778 | }), q = (m = W(regeneratorRuntime.mark(function e() { 779 | var r, t, n, a, s; 780 | return regeneratorRuntime.wrap(function(e) { 781 | for (;;) switch (e.prev = e.next) { 782 | case 0: 783 | return r = $.getCommandKeyword("libev", "getAllTraffic"), e.next = 3, ee(r); 784 | 785 | case 3: 786 | if (t = e.sent, n = void 0, "stat:" !== t.substr(0, 5)) { 787 | e.next = 9; 788 | break; 789 | } 790 | n = JSON.parse(t.substr(5)), e.next = 10; 791 | break; 792 | 793 | case 9: 794 | throw new Error("getAllTrafficFromLibev, received unknown message"); 795 | 796 | case 10: 797 | return a = Object.keys(n), s = [], a.forEach(function(e) { 798 | var r = { 799 | port: Number(e), 800 | traffic: Number(n[e]) 801 | }; 802 | s.push(r); 803 | }), e.abrupt("return", s); 804 | 805 | case 15: 806 | case "end": 807 | return e.stop(); 808 | } 809 | }, e, this); 810 | })), function() { 811 | return m.apply(this, arguments); 812 | }), j = (g = W(regeneratorRuntime.mark(function e(r) { 813 | var t, n, a; 814 | return regeneratorRuntime.wrap(function(e) { 815 | for (;;) switch (e.prev = e.next) { 816 | case 0: 817 | if (!(!r || "object" !== (void 0 === r ? "undefined" : y(r)) || !r.hasOwnProperty("port") || !r.hasOwnProperty("password") || isNaN(r.port) || !Number.isInteger(r.port) || r.port < 1 || r.port > 65535 || "string" != typeof r.password || r.password.length < 1)) { 818 | e.next = 2; 819 | break; 820 | } 821 | throw new Error("illegal argument"); 822 | 823 | case 2: 824 | return t = $.getCommandKeyword("libev", "add"), n = t + ": " + JSON.stringify({ 825 | server_port: r.port, 826 | password: r.password, 827 | method: r.method 828 | }), e.next = 7, ee(n); 829 | 830 | case 7: 831 | if ("ok" !== (a = e.sent).substr(0, 2)) { 832 | e.next = 11; 833 | break; 834 | } 835 | e.next = 16; 836 | break; 837 | 838 | case 11: 839 | if ("err" !== a.substr(0, 3)) { 840 | e.next = 15; 841 | break; 842 | } 843 | throw new Error("illegal command"); 844 | 845 | case 15: 846 | throw new Error("sendAddToLibev, received unknown message:" + a); 847 | 848 | case 16: 849 | case 17: 850 | case "end": 851 | return e.stop(); 852 | } 853 | }, e, this); 854 | })), function(e) { 855 | return g.apply(this, arguments); 856 | }), F = (d = W(regeneratorRuntime.mark(function e(r) { 857 | var t, n, a; 858 | return regeneratorRuntime.wrap(function(e) { 859 | for (;;) switch (e.prev = e.next) { 860 | case 0: 861 | if (!(!r || "object" !== (void 0 === r ? "undefined" : y(r)) || !r.hasOwnProperty("port") || !r.hasOwnProperty("password") || isNaN(r.port) || !Number.isInteger(r.port) || r.port < 1 || r.port > 65535 || "string" != typeof r.password || r.password.length < 1)) { 862 | e.next = 2; 863 | break; 864 | } 865 | throw new Error("illegal argument"); 866 | 867 | case 2: 868 | return t = $.getCommandKeyword("python", "add"), n = t + ": " + JSON.stringify({ 869 | server_port: r.port, 870 | password: r.password 871 | }), e.next = 7, ee(n); 872 | 873 | case 7: 874 | if ("ok" !== (a = e.sent).substr(0, 2)) { 875 | e.next = 11; 876 | break; 877 | } 878 | e.next = 16; 879 | break; 880 | 881 | case 11: 882 | if ("err" !== a.substr(0, 3)) { 883 | e.next = 15; 884 | break; 885 | } 886 | throw new Error("illegal command"); 887 | 888 | case 15: 889 | throw new Error("sendAddToPython, received unknown message:" + a); 890 | 891 | case 16: 892 | case 17: 893 | case "end": 894 | return e.stop(); 895 | } 896 | }, e, this); 897 | })), function(e) { 898 | return d.apply(this, arguments); 899 | }), J = (w = W(regeneratorRuntime.mark(function e(r) { 900 | var t, n; 901 | return regeneratorRuntime.wrap(function(e) { 902 | for (;;) switch (e.prev = e.next) { 903 | case 0: 904 | if (!(isNaN(r) || !Number.isInteger(r) || r < 1 || r > 65535)) { 905 | e.next = 2; 906 | break; 907 | } 908 | throw new Error("illegal argument"); 909 | 910 | case 2: 911 | return e.next = 5, N(); 912 | 913 | case 5: 914 | return t = e.sent, n = t.map(function(e) { 915 | return e.port; 916 | }), e.abrupt("return", n.includes(r)); 917 | 918 | case 8: 919 | case "end": 920 | return e.stop(); 921 | } 922 | }, e, this); 923 | })), function(e) { 924 | return w.apply(this, arguments); 925 | }), L = (b = W(regeneratorRuntime.mark(function e(r) { 926 | var t; 927 | return regeneratorRuntime.wrap(function(e) { 928 | for (;;) switch (e.prev = e.next) { 929 | case 0: 930 | if (!(isNaN(r) || !Number.isInteger(r) || r < 1 || r > 65535)) { 931 | e.next = 2; 932 | break; 933 | } 934 | throw new Error("illegal argument"); 935 | 936 | case 2: 937 | return e.next = 5, Q.test(r); 938 | 939 | case 5: 940 | return t = e.sent, e.abrupt("return", t); 941 | 942 | case 7: 943 | case "end": 944 | return e.stop(); 945 | } 946 | }, e, this); 947 | })), function(e) { 948 | return b.apply(this, arguments); 949 | }), K = (x = W(regeneratorRuntime.mark(function e(r) { 950 | var t, n, a; 951 | return regeneratorRuntime.wrap(function(e) { 952 | for (;;) switch (e.prev = e.next) { 953 | case 0: 954 | if (!(isNaN(r) || !Number.isInteger(r) || r < 1 || r > 65535)) { 955 | e.next = 2; 956 | break; 957 | } 958 | throw new Error("illegal argument"); 959 | 960 | case 2: 961 | return t = $.getCommandKeyword("libev", "remove"), n = t + ": " + JSON.stringify({ 962 | server_port: r 963 | }), e.next = 7, ee(n); 964 | 965 | case 7: 966 | if ("ok" !== (a = e.sent).substr(0, 2)) { 967 | e.next = 11; 968 | break; 969 | } 970 | e.next = 16; 971 | break; 972 | 973 | case 11: 974 | if ("err" !== a.substr(0, 3)) { 975 | e.next = 15; 976 | break; 977 | } 978 | throw new Error("illegal command"); 979 | 980 | case 15: 981 | throw new Error("sendRemoveFromLibev, received unknown message:" + a); 982 | 983 | case 16: 984 | case 17: 985 | case "end": 986 | return e.stop(); 987 | } 988 | }, e, this); 989 | })), function(e) { 990 | return x.apply(this, arguments); 991 | }), C = (v = W(regeneratorRuntime.mark(function e(r) { 992 | var t, n, a; 993 | return regeneratorRuntime.wrap(function(e) { 994 | for (;;) switch (e.prev = e.next) { 995 | case 0: 996 | if (!(isNaN(r) || !Number.isInteger(r) || r < 1 || r > 65535)) { 997 | e.next = 2; 998 | break; 999 | } 1000 | throw new Error("illegal argument"); 1001 | 1002 | case 2: 1003 | return t = $.getCommandKeyword("python", "remove"), n = t + ": " + JSON.stringify({ 1004 | server_port: r 1005 | }), e.next = 7, ee(n); 1006 | 1007 | case 7: 1008 | if ("ok" !== (a = e.sent).substr(0, 2)) { 1009 | e.next = 11; 1010 | break; 1011 | } 1012 | e.next = 16; 1013 | break; 1014 | 1015 | case 11: 1016 | if ("err" !== a.substr(0, 3)) { 1017 | e.next = 15; 1018 | break; 1019 | } 1020 | throw new Error("illegal command"); 1021 | 1022 | case 15: 1023 | throw new Error("sendRemoveFromPython, received unknown message:" + a); 1024 | 1025 | case 16: 1026 | case 17: 1027 | case "end": 1028 | return e.stop(); 1029 | } 1030 | }, e, this); 1031 | })), function(e) { 1032 | return v.apply(this, arguments); 1033 | }); 1034 | function W(e) { 1035 | return function() { 1036 | var r = e.apply(this, arguments); 1037 | return new Promise(function(e, t) { 1038 | return function n(a, s) { 1039 | try { 1040 | var o = r[a](s), i = o.value; 1041 | } catch (e) { 1042 | return void t(e); 1043 | } 1044 | if (!o.done) return Promise.resolve(i).then(function(e) { 1045 | n("next", e); 1046 | }, function(e) { 1047 | n("throw", e); 1048 | }); 1049 | e(i); 1050 | }("next"); 1051 | }); 1052 | }; 1053 | } 1054 | var B = t(9), M = t(2), D = t(3), G = new (t(8))(), H = t(1), z = (t(0)("service"), 1055 | B.createSocket("unix_dgram")), Q = t(7), U = t(6), V = D.resolve(__dirname, "/tmp/shadowsocks-manager.sock"), X = D.resolve(__dirname, "/tmp/ss-controller.sock"), Y = process.env.LOGIN_PASSWORD, Z = { 1056 | type: null, 1057 | getType: function() { 1058 | var e = W(regeneratorRuntime.mark(function e() { 1059 | var r; 1060 | return regeneratorRuntime.wrap(function(e) { 1061 | for (;;) switch (e.prev = e.next) { 1062 | case 0: 1063 | if (!this.type) { 1064 | e.next = 9; 1065 | break; 1066 | } 1067 | if ("libev" !== this.type && "python" !== this.type) { 1068 | e.next = 5; 1069 | break; 1070 | } 1071 | return e.abrupt("return", this.type); 1072 | 1073 | case 5: 1074 | throw new Error("unknown shadowsocks type"); 1075 | 1076 | case 6: 1077 | e.next = 22; 1078 | break; 1079 | 1080 | case 9: 1081 | return e.next = 11, ee("ping"); 1082 | 1083 | case 11: 1084 | if ("stat:" !== (r = e.sent).substr(0, 5)) { 1085 | e.next = 16; 1086 | break; 1087 | } 1088 | this.type = "libev", e.next = 21; 1089 | break; 1090 | 1091 | case 16: 1092 | if ("pong" !== r.substr(0, 5)) { 1093 | e.next = 20; 1094 | break; 1095 | } 1096 | this.type = "libev", e.next = 21; 1097 | break; 1098 | 1099 | case 20: 1100 | throw new Error("shadowsocksType.getType, received unknown message"); 1101 | 1102 | case 21: 1103 | return e.abrupt("return", this.type); 1104 | 1105 | case 22: 1106 | case 23: 1107 | case "end": 1108 | return e.stop(); 1109 | } 1110 | }, e, this); 1111 | })); 1112 | return function() { 1113 | return e.apply(this, arguments); 1114 | }; 1115 | }() 1116 | }, $ = { 1117 | commandKeywords: { 1118 | libev: { 1119 | ping: "ping", 1120 | getAllPorts: "list", 1121 | getAllTraffic: "ping", 1122 | add: "add", 1123 | remove: "remove" 1124 | }, 1125 | python: { 1126 | ping: "ping", 1127 | getAllPorts: "", 1128 | getAllTraffic: "", 1129 | add: "add", 1130 | remove: "remove" 1131 | } 1132 | }, 1133 | getCommandKeyword: function(e, r) { 1134 | if ("libev" !== e && "python" !== e) throw new Error("illegal argument"); 1135 | if ("ping" !== r && "getAllPorts" !== r && "getAllTraffic" !== r && "add" !== r && "remove" !== r) throw new Error("illegal argument"); 1136 | return this.commandKeywords[e][r]; 1137 | } 1138 | }; 1139 | function ee(e) { 1140 | if (!e || "string" != typeof e) throw new Error("illegal argument"); 1141 | if ("ping" !== e && "list" !== e && "add: " !== e.substr(0, 5) && "remove: " !== e.substr(0, 8)) throw new Error("illegal argument"); 1142 | if ("add: " === e.substr(0, 5)) { 1143 | var r = e.substr(5); 1144 | if (!re(r)) throw new Error("illegal argument"); 1145 | var t = JSON.parse(r); 1146 | if (!t.hasOwnProperty("server_port") || !t.hasOwnProperty("password") || isNaN(t.server_port) || !Number.isInteger(t.server_port) || t.server_port < 1 || t.server_port > 65535 || "string" != typeof t.password || t.password.length < 1) throw new Error("illegal argument"); 1147 | } 1148 | if ("remove: " === e.substr(0, 8)) { 1149 | var n = e.substr(8); 1150 | if (!re(n)) throw new Error("illegal argument"); 1151 | var a = JSON.parse(n); 1152 | if (!a.hasOwnProperty("server_port") || isNaN(a.server_port) || !Number.isInteger(a.server_port) || a.server_port < 1 || a.server_port > 65535) throw new Error("illegal argument"); 1153 | } 1154 | return G.acquire("key", function() { 1155 | return new Promise(function(r, t) { 1156 | var n = !1; 1157 | z.once("message", function(e) { 1158 | n = !0; 1159 | var t = new String(e); 1160 | r(t); 1161 | }); 1162 | try { 1163 | !function(e) { 1164 | var r = new Buffer(e); 1165 | z.send(r, 0, r.length, V, function(e) { 1166 | if (e) throw new Error("shadowsocks unreachable"); 1167 | }); 1168 | }(e); 1169 | } catch (e) { 1170 | throw z.removeAllListeners("message"), e; 1171 | } 1172 | setTimeout(function() { 1173 | n || (z.removeAllListeners("message"), t(new Error("shadowsocks no response"))); 1174 | }, 1e3); 1175 | }); 1176 | }, {}).then(function(e) { 1177 | return e; 1178 | }); 1179 | } 1180 | function re(e) { 1181 | try { 1182 | JSON.parse(e); 1183 | } catch (e) { 1184 | return !1; 1185 | } 1186 | return !0; 1187 | } 1188 | M.existsSync(X) && M.unlinkSync(X), z.bind(X), z.on("error", function(e) { 1189 | throw new Error("client on error, shadowsocks error", e); 1190 | }), k(), setInterval(function() { 1191 | k(); 1192 | }, 3e3), e.exports.login = E, e.exports.addPort = R, e.exports.getAllPorts = N, 1193 | e.exports.getAllTraffic = S, e.exports.ping = I, e.exports.removePort = O; 1194 | }, function(e, r, t) { 1195 | "use strict"; 1196 | var n, a, s, o, i, c, u = (n = g(regeneratorRuntime.mark(function e(r, t) { 1197 | var n, a; 1198 | return regeneratorRuntime.wrap(function(e) { 1199 | for (;;) switch (e.prev = e.next) { 1200 | case 0: 1201 | if (r.checkBody("password", "Invalid password").notEmpty(), !(n = r.validationErrors())) { 1202 | e.next = 4; 1203 | break; 1204 | } 1205 | return e.abrupt("return", t.status(400).send({ 1206 | error: n 1207 | })); 1208 | 1209 | case 4: 1210 | return e.prev = 4, e.next = 7, d.login(r.body.password); 1211 | 1212 | case 7: 1213 | return a = w.sign({}, v, { 1214 | expiresIn: 86400 1215 | }), e.abrupt("return", t.status(201).send({ 1216 | token: a 1217 | })); 1218 | 1219 | case 11: 1220 | if (e.prev = 11, e.t0 = e.catch(4), "invalid password" !== e.t0.message) { 1221 | e.next = 15; 1222 | break; 1223 | } 1224 | return e.abrupt("return", t.status(401).end()); 1225 | 1226 | case 15: 1227 | return e.abrupt("return", t.status(500).end({ 1228 | error: e.t0 1229 | })); 1230 | 1231 | case 16: 1232 | case 17: 1233 | case "end": 1234 | return e.stop(); 1235 | } 1236 | }, e, this, [ [ 4, 11 ] ]); 1237 | })), function(e, r) { 1238 | return n.apply(this, arguments); 1239 | }), p = (a = g(regeneratorRuntime.mark(function e(r, t) { 1240 | var n; 1241 | return regeneratorRuntime.wrap(function(e) { 1242 | for (;;) switch (e.prev = e.next) { 1243 | case 0: 1244 | if ("string" == typeof r.body.port && (r.body.port = parseInt(r.body.port)), r.checkBody("port", "Invalid port number").isInt({ 1245 | min: 1, 1246 | max: 65535 1247 | }), r.checkBody("password", "Invalid password").notEmpty(), r.checkBody("method", "Invalid encryption method").optional().isIn([ "aes-128-gcm", "aes-192-gcm", "aes-256-gcm", "aes-128-cfb", "aes-192-cfb", "aes-256-cfb", "aes-128-ctr", "aes-192-ctr", "aes-256-ctr", "camellia-128-cfb", "camellia-192-cfb", "camellia-256-cfb", "bf-cfb", "chacha20-ietf-poly1305", "xchacha20-ietf-poly1305", "salsa20", "chacha20", "chacha20-ietf" ]), 1248 | !(n = r.validationErrors())) { 1249 | e.next = 8; 1250 | break; 1251 | } 1252 | return e.abrupt("return", t.status(400).send({ 1253 | error: n 1254 | })); 1255 | 1256 | case 8: 1257 | return r.body.method || (r.body.method = "aes-256-cfb"), e.prev = 11, e.next = 14, 1258 | d.addPort(r.body); 1259 | 1260 | case 14: 1261 | return e.abrupt("return", t.status(201).end()); 1262 | 1263 | case 17: 1264 | if (e.prev = 17, e.t0 = e.catch(11), "port already exists from shadowsocks" !== e.t0.message) { 1265 | e.next = 21; 1266 | break; 1267 | } 1268 | return e.abrupt("return", t.status(409).end()); 1269 | 1270 | case 21: 1271 | if ("port not available from operating system" !== e.t0.message) { 1272 | e.next = 24; 1273 | break; 1274 | } 1275 | return e.abrupt("return", t.status(410).end()); 1276 | 1277 | case 24: 1278 | if ("shadowsocks failed adding port" !== e.t0.message) { 1279 | e.next = 27; 1280 | break; 1281 | } 1282 | return e.abrupt("return", t.status(422).end()); 1283 | 1284 | case 27: 1285 | if ("operating system failed adding port" !== e.t0.message) { 1286 | e.next = 30; 1287 | break; 1288 | } 1289 | return e.abrupt("return", t.status(427).end()); 1290 | 1291 | case 30: 1292 | if ("shadowsocks unreachable" !== e.t0.message) { 1293 | e.next = 33; 1294 | break; 1295 | } 1296 | return e.abrupt("return", t.status(424).end()); 1297 | 1298 | case 33: 1299 | if ("shadowsocks no response" !== e.t0.message) { 1300 | e.next = 36; 1301 | break; 1302 | } 1303 | return e.abrupt("return", t.status(425).end()); 1304 | 1305 | case 36: 1306 | return e.abrupt("return", t.status(500).send({ 1307 | error: e.t0 1308 | })); 1309 | 1310 | case 38: 1311 | case 39: 1312 | case "end": 1313 | return e.stop(); 1314 | } 1315 | }, e, this, [ [ 11, 17 ] ]); 1316 | })), function(e, r) { 1317 | return a.apply(this, arguments); 1318 | }), f = (s = g(regeneratorRuntime.mark(function e(r, t) { 1319 | var n; 1320 | return regeneratorRuntime.wrap(function(e) { 1321 | for (;;) switch (e.prev = e.next) { 1322 | case 0: 1323 | return e.prev = 0, e.next = 3, d.getAllPorts(); 1324 | 1325 | case 3: 1326 | return n = e.sent, e.abrupt("return", t.status(200).send(n)); 1327 | 1328 | case 7: 1329 | if (e.prev = 7, e.t0 = e.catch(0), "shadowsocks unreachable" !== e.t0.message) { 1330 | e.next = 11; 1331 | break; 1332 | } 1333 | return e.abrupt("return", t.status(424).end()); 1334 | 1335 | case 11: 1336 | if ("shadowsocks no response" !== e.t0.message) { 1337 | e.next = 14; 1338 | break; 1339 | } 1340 | return e.abrupt("return", t.status(425).end()); 1341 | 1342 | case 14: 1343 | return e.abrupt("return", t.status(500).send({ 1344 | error: e.t0 1345 | })); 1346 | 1347 | case 16: 1348 | case 17: 1349 | case "end": 1350 | return e.stop(); 1351 | } 1352 | }, e, this, [ [ 0, 7 ] ]); 1353 | })), function(e, r) { 1354 | return s.apply(this, arguments); 1355 | }), l = (o = g(regeneratorRuntime.mark(function e(r, t) { 1356 | var n; 1357 | return regeneratorRuntime.wrap(function(e) { 1358 | for (;;) switch (e.prev = e.next) { 1359 | case 0: 1360 | return e.prev = 0, e.next = 3, d.getAllTraffic(); 1361 | 1362 | case 3: 1363 | return n = e.sent, e.abrupt("return", t.status(200).send(n)); 1364 | 1365 | case 7: 1366 | if (e.prev = 7, e.t0 = e.catch(0), "shadowsocks unreachable" !== e.t0.message) { 1367 | e.next = 11; 1368 | break; 1369 | } 1370 | return e.abrupt("return", t.status(424).end()); 1371 | 1372 | case 11: 1373 | if ("shadowsocks no response" !== e.t0.message) { 1374 | e.next = 14; 1375 | break; 1376 | } 1377 | return e.abrupt("return", t.status(425).end()); 1378 | 1379 | case 14: 1380 | return e.abrupt("return", t.status(500).send({ 1381 | error: e.t0 1382 | })); 1383 | 1384 | case 16: 1385 | case 17: 1386 | case "end": 1387 | return e.stop(); 1388 | } 1389 | }, e, this, [ [ 0, 7 ] ]); 1390 | })), function(e, r) { 1391 | return o.apply(this, arguments); 1392 | }), h = (i = g(regeneratorRuntime.mark(function e(r, t) { 1393 | var n; 1394 | return regeneratorRuntime.wrap(function(e) { 1395 | for (;;) switch (e.prev = e.next) { 1396 | case 0: 1397 | return e.prev = 0, e.next = 3, d.ping(); 1398 | 1399 | case 3: 1400 | return n = e.sent, e.abrupt("return", t.status(200).send(n)); 1401 | 1402 | case 7: 1403 | if (e.prev = 7, e.t0 = e.catch(0), "shadowsocks unreachable" !== e.t0.message) { 1404 | e.next = 11; 1405 | break; 1406 | } 1407 | return e.abrupt("return", t.status(424).end()); 1408 | 1409 | case 11: 1410 | if ("shadowsocks no response" !== e.t0.message) { 1411 | e.next = 14; 1412 | break; 1413 | } 1414 | return e.abrupt("return", t.status(425).end()); 1415 | 1416 | case 14: 1417 | return e.abrupt("return", t.status(500).send({ 1418 | error: e.t0 1419 | })); 1420 | 1421 | case 16: 1422 | case 17: 1423 | case "end": 1424 | return e.stop(); 1425 | } 1426 | }, e, this, [ [ 0, 7 ] ]); 1427 | })), function(e, r) { 1428 | return i.apply(this, arguments); 1429 | }), m = (c = g(regeneratorRuntime.mark(function e(r, t) { 1430 | var n; 1431 | return regeneratorRuntime.wrap(function(e) { 1432 | for (;;) switch (e.prev = e.next) { 1433 | case 0: 1434 | if ("string" == typeof r.query.port && (r.query.port = parseInt(r.query.port)), 1435 | r.checkQuery("port", "Invalid port number").isInt({ 1436 | min: 1, 1437 | max: 65535 1438 | }), !(n = r.validationErrors())) { 1439 | e.next = 6; 1440 | break; 1441 | } 1442 | return e.abrupt("return", t.status(400).send({ 1443 | error: n 1444 | })); 1445 | 1446 | case 6: 1447 | return e.prev = 7, e.next = 10, d.removePort(Number(r.query.port)); 1448 | 1449 | case 10: 1450 | return e.abrupt("return", t.status(204).end()); 1451 | 1452 | case 13: 1453 | if (e.prev = 13, e.t0 = e.catch(7), "shadowsocks failed removing port" !== e.t0.message) { 1454 | e.next = 17; 1455 | break; 1456 | } 1457 | return e.abrupt("return", t.status(422).end()); 1458 | 1459 | case 17: 1460 | if ("operating system failed removing port" !== e.t0.message) { 1461 | e.next = 20; 1462 | break; 1463 | } 1464 | return e.abrupt("return", t.status(427).end()); 1465 | 1466 | case 20: 1467 | if ("shadowsocks unreachable" !== e.t0.message) { 1468 | e.next = 23; 1469 | break; 1470 | } 1471 | return e.abrupt("return", t.status(424).end()); 1472 | 1473 | case 23: 1474 | if ("shadowsocks no response" !== e.t0.message) { 1475 | e.next = 26; 1476 | break; 1477 | } 1478 | return e.abrupt("return", t.status(425).end()); 1479 | 1480 | case 26: 1481 | return e.abrupt("return", t.status(500).send({ 1482 | error: e.t0 1483 | })); 1484 | 1485 | case 28: 1486 | case 29: 1487 | case "end": 1488 | return e.stop(); 1489 | } 1490 | }, e, this, [ [ 7, 13 ] ]); 1491 | })), function(e, r) { 1492 | return c.apply(this, arguments); 1493 | }); 1494 | function g(e) { 1495 | return function() { 1496 | var r = e.apply(this, arguments); 1497 | return new Promise(function(e, t) { 1498 | return function n(a, s) { 1499 | try { 1500 | var o = r[a](s), i = o.value; 1501 | } catch (e) { 1502 | return void t(e); 1503 | } 1504 | if (!o.done) return Promise.resolve(i).then(function(e) { 1505 | n("next", e); 1506 | }, function(e) { 1507 | n("throw", e); 1508 | }); 1509 | e(i); 1510 | }("next"); 1511 | }); 1512 | }; 1513 | } 1514 | t(1); 1515 | var d = t(10), w = t(5), b = t(4), x = (t(0)("controller"), process.env.LOGIN_PASSWORD), v = b.createHash("sha256").update(x + "W93Ciowi2398(@qi30vmbj02i@WWSoekwoiK").digest("hex"); 1516 | e.exports.login = u, e.exports.addPort = p, e.exports.getAllPorts = f, e.exports.getAllTraffic = l, 1517 | e.exports.ping = h, e.exports.removePort = m; 1518 | }, function(e, r) { 1519 | e.exports = require("passport-jwt"); 1520 | }, function(e, r) { 1521 | e.exports = require("passport"); 1522 | }, function(e, r) { 1523 | e.exports = require("express-validator"); 1524 | }, function(e, r) { 1525 | e.exports = require("body-parser"); 1526 | }, function(e, r) { 1527 | e.exports = require("https"); 1528 | }, function(e, r) { 1529 | e.exports = require("express"); 1530 | }, function(e, r) { 1531 | e.exports = require("dotenv"); 1532 | }, function(e, r, t) { 1533 | "use strict"; 1534 | t(18).config(); 1535 | var n = t(17), a = t(2), s = t(16), o = t(15), i = t(14), c = t(4), u = t(13), p = t(12), f = p.Strategy, l = p.ExtractJwt, h = process.env.LOGIN_PASSWORD, m = c.createHash("sha256").update(h + "W93Ciowi2398(@qi30vmbj02i@WWSoekwoiK").digest("hex"), g = void 0; 1536 | Number(process.env.LISTEN_PORT) && Number(process.env.LISTEN_PORT) >= 1 && Number(process.env.LISTEN_PORT) <= 65535 ? g = process.env.LISTEN_PORT : (console.warn("LISTEN_PORT invalid. Using 4001."), 1537 | g = 4001); 1538 | var d = { 1539 | jwtFromRequest: l.fromAuthHeaderAsBearerToken(), 1540 | secretOrKey: m 1541 | }; 1542 | u.use(new f(d, function(e, r) { 1543 | return r(null, { 1544 | id: 1 1545 | }); 1546 | })); 1547 | var w = u.authenticate("jwt", { 1548 | session: !1 1549 | }), b = void 0, x = void 0; 1550 | try { 1551 | b = a.readFileSync("./server.key", "utf8"), x = a.readFileSync("./server.cert", "utf8"); 1552 | } catch (e) { 1553 | console.error("reading ./server.key or ./server.cert failed"), process.exit(1); 1554 | } 1555 | var v = { 1556 | key: b, 1557 | cert: x 1558 | }, y = n(), k = void 0; 1559 | try { 1560 | k = s.createServer(v, y); 1561 | } catch (e) { 1562 | console.error("ssl key and/or certificate error corrupted"), process.exit(2); 1563 | } 1564 | y.use(o.json()), y.use(o.urlencoded({ 1565 | extended: !0 1566 | })), y.use(i()); 1567 | var E = t(11); 1568 | y.post("/login", E.login), y.post("/", w, E.addPort), y.delete("/", w, E.removePort), 1569 | y.get("/all", w, E.getAllPorts), y.get("/traffic/all", w, E.getAllTraffic), y.get("/ping", w, E.ping), 1570 | k.listen(g, function() { 1571 | console.log("listening on port", g); 1572 | }).on("error", function(e) { 1573 | console.error("express server error: " + e), process.exit(3); 1574 | }), e.exports = y; 1575 | }, function(e, r) { 1576 | e.exports = require("babel-polyfill"); 1577 | }, function(e, r, t) { 1578 | t(20), e.exports = t(19); 1579 | } ]); -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.3' 2 | services: 3 | shadow-rest: 4 | restart: always 5 | network_mode: host 6 | container_name: shadow-rest 7 | image: shadow-rest:1.0.0 8 | volumes: 9 | - shadow-configs:/root/.shadowsocks/ 10 | 11 | volumes: 12 | shadow-configs: -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shadowsocks-restful-api", 3 | "version": "0.1.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.5", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 10 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 11 | "requires": { 12 | "mime-types": "~2.1.18", 13 | "negotiator": "0.6.1" 14 | } 15 | }, 16 | "array-flatten": { 17 | "version": "1.1.1", 18 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 19 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 20 | }, 21 | "async-lock": { 22 | "version": "1.1.3", 23 | "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.1.3.tgz", 24 | "integrity": "sha512-nxlfFLGfCJ1r7p9zhR5OuL6jYkDd9P7FqSitfLji+C1NdyhCz4+rWW3kiPiyPASHhN7VlsKEvRWWbnME9lYngw==" 25 | }, 26 | "babel-polyfill": { 27 | "version": "6.26.0", 28 | "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.26.0.tgz", 29 | "integrity": "sha1-N5k3q8Z9eJWXCtxiHyhM2WbPIVM=", 30 | "requires": { 31 | "babel-runtime": "^6.26.0", 32 | "core-js": "^2.5.0", 33 | "regenerator-runtime": "^0.10.5" 34 | } 35 | }, 36 | "babel-runtime": { 37 | "version": "6.26.0", 38 | "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", 39 | "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", 40 | "requires": { 41 | "core-js": "^2.4.0", 42 | "regenerator-runtime": "^0.11.0" 43 | }, 44 | "dependencies": { 45 | "regenerator-runtime": { 46 | "version": "0.11.1", 47 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", 48 | "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" 49 | } 50 | } 51 | }, 52 | "bindings": { 53 | "version": "1.3.0", 54 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.3.0.tgz", 55 | "integrity": "sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw==" 56 | }, 57 | "bluebird": { 58 | "version": "2.11.0", 59 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.11.0.tgz", 60 | "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" 61 | }, 62 | "body-parser": { 63 | "version": "1.18.3", 64 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", 65 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", 66 | "requires": { 67 | "bytes": "3.0.0", 68 | "content-type": "~1.0.4", 69 | "debug": "2.6.9", 70 | "depd": "~1.1.2", 71 | "http-errors": "~1.6.3", 72 | "iconv-lite": "0.4.23", 73 | "on-finished": "~2.3.0", 74 | "qs": "6.5.2", 75 | "raw-body": "2.3.3", 76 | "type-is": "~1.6.16" 77 | }, 78 | "dependencies": { 79 | "debug": { 80 | "version": "2.6.9", 81 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 82 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 83 | "requires": { 84 | "ms": "2.0.0" 85 | } 86 | } 87 | } 88 | }, 89 | "buffer-equal-constant-time": { 90 | "version": "1.0.1", 91 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", 92 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" 93 | }, 94 | "bytes": { 95 | "version": "3.0.0", 96 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 97 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 98 | }, 99 | "commander": { 100 | "version": "2.15.1", 101 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz", 102 | "integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag==" 103 | }, 104 | "content-disposition": { 105 | "version": "0.5.2", 106 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 107 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 108 | }, 109 | "content-type": { 110 | "version": "1.0.4", 111 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 112 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 113 | }, 114 | "cookie": { 115 | "version": "0.3.1", 116 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 117 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 118 | }, 119 | "cookie-signature": { 120 | "version": "1.0.6", 121 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 122 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 123 | }, 124 | "core-js": { 125 | "version": "2.5.7", 126 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", 127 | "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" 128 | }, 129 | "debug": { 130 | "version": "3.1.0", 131 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 132 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 133 | "requires": { 134 | "ms": "2.0.0" 135 | } 136 | }, 137 | "depd": { 138 | "version": "1.1.2", 139 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 140 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 141 | }, 142 | "destroy": { 143 | "version": "1.0.4", 144 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 145 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 146 | }, 147 | "dotenv": { 148 | "version": "6.0.0", 149 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-6.0.0.tgz", 150 | "integrity": "sha512-FlWbnhgjtwD+uNLUGHbMykMOYQaTivdHEmYwAKFjn6GKe/CqY0fNae93ZHTd20snh9ZLr8mTzIL9m0APQ1pjQg==" 151 | }, 152 | "ecdsa-sig-formatter": { 153 | "version": "1.0.10", 154 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.10.tgz", 155 | "integrity": "sha1-HFlQAPBKiJffuFAAiSoPTDOvhsM=", 156 | "requires": { 157 | "safe-buffer": "^5.0.1" 158 | } 159 | }, 160 | "ee-first": { 161 | "version": "1.1.1", 162 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 163 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 164 | }, 165 | "encodeurl": { 166 | "version": "1.0.2", 167 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 168 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 169 | }, 170 | "escape-html": { 171 | "version": "1.0.3", 172 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 173 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 174 | }, 175 | "etag": { 176 | "version": "1.8.1", 177 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 178 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 179 | }, 180 | "express": { 181 | "version": "4.16.3", 182 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.3.tgz", 183 | "integrity": "sha1-avilAjUNsyRuzEvs9rWjTSL37VM=", 184 | "requires": { 185 | "accepts": "~1.3.5", 186 | "array-flatten": "1.1.1", 187 | "body-parser": "1.18.2", 188 | "content-disposition": "0.5.2", 189 | "content-type": "~1.0.4", 190 | "cookie": "0.3.1", 191 | "cookie-signature": "1.0.6", 192 | "debug": "2.6.9", 193 | "depd": "~1.1.2", 194 | "encodeurl": "~1.0.2", 195 | "escape-html": "~1.0.3", 196 | "etag": "~1.8.1", 197 | "finalhandler": "1.1.1", 198 | "fresh": "0.5.2", 199 | "merge-descriptors": "1.0.1", 200 | "methods": "~1.1.2", 201 | "on-finished": "~2.3.0", 202 | "parseurl": "~1.3.2", 203 | "path-to-regexp": "0.1.7", 204 | "proxy-addr": "~2.0.3", 205 | "qs": "6.5.1", 206 | "range-parser": "~1.2.0", 207 | "safe-buffer": "5.1.1", 208 | "send": "0.16.2", 209 | "serve-static": "1.13.2", 210 | "setprototypeof": "1.1.0", 211 | "statuses": "~1.4.0", 212 | "type-is": "~1.6.16", 213 | "utils-merge": "1.0.1", 214 | "vary": "~1.1.2" 215 | }, 216 | "dependencies": { 217 | "body-parser": { 218 | "version": "1.18.2", 219 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", 220 | "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", 221 | "requires": { 222 | "bytes": "3.0.0", 223 | "content-type": "~1.0.4", 224 | "debug": "2.6.9", 225 | "depd": "~1.1.1", 226 | "http-errors": "~1.6.2", 227 | "iconv-lite": "0.4.19", 228 | "on-finished": "~2.3.0", 229 | "qs": "6.5.1", 230 | "raw-body": "2.3.2", 231 | "type-is": "~1.6.15" 232 | } 233 | }, 234 | "debug": { 235 | "version": "2.6.9", 236 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 237 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 238 | "requires": { 239 | "ms": "2.0.0" 240 | } 241 | }, 242 | "iconv-lite": { 243 | "version": "0.4.19", 244 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", 245 | "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" 246 | }, 247 | "qs": { 248 | "version": "6.5.1", 249 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", 250 | "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" 251 | }, 252 | "raw-body": { 253 | "version": "2.3.2", 254 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", 255 | "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", 256 | "requires": { 257 | "bytes": "3.0.0", 258 | "http-errors": "1.6.2", 259 | "iconv-lite": "0.4.19", 260 | "unpipe": "1.0.0" 261 | }, 262 | "dependencies": { 263 | "depd": { 264 | "version": "1.1.1", 265 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", 266 | "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" 267 | }, 268 | "http-errors": { 269 | "version": "1.6.2", 270 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", 271 | "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", 272 | "requires": { 273 | "depd": "1.1.1", 274 | "inherits": "2.0.3", 275 | "setprototypeof": "1.0.3", 276 | "statuses": ">= 1.3.1 < 2" 277 | } 278 | }, 279 | "setprototypeof": { 280 | "version": "1.0.3", 281 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", 282 | "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" 283 | } 284 | } 285 | }, 286 | "statuses": { 287 | "version": "1.4.0", 288 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 289 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 290 | } 291 | } 292 | }, 293 | "express-validator": { 294 | "version": "5.2.0", 295 | "resolved": "https://registry.npmjs.org/express-validator/-/express-validator-5.2.0.tgz", 296 | "integrity": "sha512-FyQ7gAaNwnIYvtfagy+fDrtzjNDFKRVjzplCPDXEu8fxSR/XBdXZHAtLR22446GWlw48LZPSKldqUVmySBWApA==", 297 | "requires": { 298 | "lodash": "^4.17.10", 299 | "validator": "^10.1.0" 300 | } 301 | }, 302 | "finalhandler": { 303 | "version": "1.1.1", 304 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 305 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 306 | "requires": { 307 | "debug": "2.6.9", 308 | "encodeurl": "~1.0.2", 309 | "escape-html": "~1.0.3", 310 | "on-finished": "~2.3.0", 311 | "parseurl": "~1.3.2", 312 | "statuses": "~1.4.0", 313 | "unpipe": "~1.0.0" 314 | }, 315 | "dependencies": { 316 | "debug": { 317 | "version": "2.6.9", 318 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 319 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 320 | "requires": { 321 | "ms": "2.0.0" 322 | } 323 | }, 324 | "statuses": { 325 | "version": "1.4.0", 326 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 327 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 328 | } 329 | } 330 | }, 331 | "forwarded": { 332 | "version": "0.1.2", 333 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 334 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 335 | }, 336 | "fresh": { 337 | "version": "0.5.2", 338 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 339 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 340 | }, 341 | "http-errors": { 342 | "version": "1.6.3", 343 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 344 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 345 | "requires": { 346 | "depd": "~1.1.2", 347 | "inherits": "2.0.3", 348 | "setprototypeof": "1.1.0", 349 | "statuses": ">= 1.4.0 < 2" 350 | } 351 | }, 352 | "iconv-lite": { 353 | "version": "0.4.23", 354 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 355 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 356 | "requires": { 357 | "safer-buffer": ">= 2.1.2 < 3" 358 | } 359 | }, 360 | "inherits": { 361 | "version": "2.0.3", 362 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 363 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 364 | }, 365 | "ipaddr.js": { 366 | "version": "1.6.0", 367 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz", 368 | "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs=" 369 | }, 370 | "jsonwebtoken": { 371 | "version": "8.3.0", 372 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.3.0.tgz", 373 | "integrity": "sha512-oge/hvlmeJCH+iIz1DwcO7vKPkNGJHhgkspk8OH3VKlw+mbi42WtD4ig1+VXRln765vxptAv+xT26Fd3cteqag==", 374 | "requires": { 375 | "jws": "^3.1.5", 376 | "lodash.includes": "^4.3.0", 377 | "lodash.isboolean": "^3.0.3", 378 | "lodash.isinteger": "^4.0.4", 379 | "lodash.isnumber": "^3.0.3", 380 | "lodash.isplainobject": "^4.0.6", 381 | "lodash.isstring": "^4.0.1", 382 | "lodash.once": "^4.0.0", 383 | "ms": "^2.1.1" 384 | }, 385 | "dependencies": { 386 | "ms": { 387 | "version": "2.1.1", 388 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", 389 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" 390 | } 391 | } 392 | }, 393 | "jwa": { 394 | "version": "1.1.6", 395 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.1.6.tgz", 396 | "integrity": "sha512-tBO/cf++BUsJkYql/kBbJroKOgHWEigTKBAjjBEmrMGYd1QMBC74Hr4Wo2zCZw6ZrVhlJPvoMrkcOnlWR/DJfw==", 397 | "requires": { 398 | "buffer-equal-constant-time": "1.0.1", 399 | "ecdsa-sig-formatter": "1.0.10", 400 | "safe-buffer": "^5.0.1" 401 | } 402 | }, 403 | "jws": { 404 | "version": "3.1.5", 405 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.1.5.tgz", 406 | "integrity": "sha512-GsCSexFADNQUr8T5HPJvayTjvPIfoyJPtLQBwn5a4WZQchcrPMPMAWcC1AzJVRDKyD6ZPROPAxgv6rfHViO4uQ==", 407 | "requires": { 408 | "jwa": "^1.1.5", 409 | "safe-buffer": "^5.0.1" 410 | } 411 | }, 412 | "lodash": { 413 | "version": "4.17.10", 414 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", 415 | "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" 416 | }, 417 | "lodash.includes": { 418 | "version": "4.3.0", 419 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", 420 | "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" 421 | }, 422 | "lodash.isboolean": { 423 | "version": "3.0.3", 424 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", 425 | "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" 426 | }, 427 | "lodash.isinteger": { 428 | "version": "4.0.4", 429 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", 430 | "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" 431 | }, 432 | "lodash.isnumber": { 433 | "version": "3.0.3", 434 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", 435 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" 436 | }, 437 | "lodash.isplainobject": { 438 | "version": "4.0.6", 439 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", 440 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" 441 | }, 442 | "lodash.isstring": { 443 | "version": "4.0.1", 444 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", 445 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" 446 | }, 447 | "lodash.once": { 448 | "version": "4.1.1", 449 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", 450 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" 451 | }, 452 | "media-typer": { 453 | "version": "0.3.0", 454 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 455 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 456 | }, 457 | "merge-descriptors": { 458 | "version": "1.0.1", 459 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 460 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 461 | }, 462 | "methods": { 463 | "version": "1.1.2", 464 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 465 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 466 | }, 467 | "mime": { 468 | "version": "1.4.1", 469 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 470 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 471 | }, 472 | "mime-db": { 473 | "version": "1.33.0", 474 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz", 475 | "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ==" 476 | }, 477 | "mime-types": { 478 | "version": "2.1.18", 479 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz", 480 | "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==", 481 | "requires": { 482 | "mime-db": "~1.33.0" 483 | } 484 | }, 485 | "ms": { 486 | "version": "2.0.0", 487 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 488 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 489 | }, 490 | "nan": { 491 | "version": "2.10.0", 492 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz", 493 | "integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==" 494 | }, 495 | "negotiator": { 496 | "version": "0.6.1", 497 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 498 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 499 | }, 500 | "on-finished": { 501 | "version": "2.3.0", 502 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 503 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 504 | "requires": { 505 | "ee-first": "1.1.1" 506 | } 507 | }, 508 | "parseurl": { 509 | "version": "1.3.2", 510 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 511 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 512 | }, 513 | "passport": { 514 | "version": "0.4.0", 515 | "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz", 516 | "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=", 517 | "requires": { 518 | "passport-strategy": "1.x.x", 519 | "pause": "0.0.1" 520 | } 521 | }, 522 | "passport-jwt": { 523 | "version": "4.0.0", 524 | "resolved": "https://registry.npmjs.org/passport-jwt/-/passport-jwt-4.0.0.tgz", 525 | "integrity": "sha512-BwC0n2GP/1hMVjR4QpnvqA61TxenUMlmfNjYNgK0ZAs0HK4SOQkHcSv4L328blNTLtHq7DbmvyNJiH+bn6C5Mg==", 526 | "requires": { 527 | "jsonwebtoken": "^8.2.0", 528 | "passport-strategy": "^1.0.0" 529 | } 530 | }, 531 | "passport-strategy": { 532 | "version": "1.0.0", 533 | "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", 534 | "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" 535 | }, 536 | "path-to-regexp": { 537 | "version": "0.1.7", 538 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 539 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 540 | }, 541 | "pause": { 542 | "version": "0.0.1", 543 | "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", 544 | "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" 545 | }, 546 | "portastic": { 547 | "version": "1.0.1", 548 | "resolved": "https://registry.npmjs.org/portastic/-/portastic-1.0.1.tgz", 549 | "integrity": "sha1-HJgF1D+uj2pAzw28d5QJGi6dDSo=", 550 | "requires": { 551 | "bluebird": "^2.9.34", 552 | "commander": "^2.8.1", 553 | "debug": "^2.2.0" 554 | }, 555 | "dependencies": { 556 | "debug": { 557 | "version": "2.6.9", 558 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 559 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 560 | "requires": { 561 | "ms": "2.0.0" 562 | } 563 | } 564 | } 565 | }, 566 | "proxy-addr": { 567 | "version": "2.0.3", 568 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.3.tgz", 569 | "integrity": "sha512-jQTChiCJteusULxjBp8+jftSQE5Obdl3k4cnmLA6WXtK6XFuWRnvVL7aCiBqaLPM8c4ph0S4tKna8XvmIwEnXQ==", 570 | "requires": { 571 | "forwarded": "~0.1.2", 572 | "ipaddr.js": "1.6.0" 573 | } 574 | }, 575 | "qs": { 576 | "version": "6.5.2", 577 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 578 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 579 | }, 580 | "range-parser": { 581 | "version": "1.2.0", 582 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 583 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 584 | }, 585 | "raw-body": { 586 | "version": "2.3.3", 587 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", 588 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", 589 | "requires": { 590 | "bytes": "3.0.0", 591 | "http-errors": "1.6.3", 592 | "iconv-lite": "0.4.23", 593 | "unpipe": "1.0.0" 594 | } 595 | }, 596 | "regenerator-runtime": { 597 | "version": "0.10.5", 598 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", 599 | "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=" 600 | }, 601 | "safe-buffer": { 602 | "version": "5.1.1", 603 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", 604 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" 605 | }, 606 | "safer-buffer": { 607 | "version": "2.1.2", 608 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 609 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 610 | }, 611 | "send": { 612 | "version": "0.16.2", 613 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 614 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 615 | "requires": { 616 | "debug": "2.6.9", 617 | "depd": "~1.1.2", 618 | "destroy": "~1.0.4", 619 | "encodeurl": "~1.0.2", 620 | "escape-html": "~1.0.3", 621 | "etag": "~1.8.1", 622 | "fresh": "0.5.2", 623 | "http-errors": "~1.6.2", 624 | "mime": "1.4.1", 625 | "ms": "2.0.0", 626 | "on-finished": "~2.3.0", 627 | "range-parser": "~1.2.0", 628 | "statuses": "~1.4.0" 629 | }, 630 | "dependencies": { 631 | "debug": { 632 | "version": "2.6.9", 633 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 634 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 635 | "requires": { 636 | "ms": "2.0.0" 637 | } 638 | }, 639 | "statuses": { 640 | "version": "1.4.0", 641 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 642 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 643 | } 644 | } 645 | }, 646 | "serve-static": { 647 | "version": "1.13.2", 648 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 649 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 650 | "requires": { 651 | "encodeurl": "~1.0.2", 652 | "escape-html": "~1.0.3", 653 | "parseurl": "~1.3.2", 654 | "send": "0.16.2" 655 | } 656 | }, 657 | "setprototypeof": { 658 | "version": "1.1.0", 659 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 660 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 661 | }, 662 | "statuses": { 663 | "version": "1.5.0", 664 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", 665 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 666 | }, 667 | "type-is": { 668 | "version": "1.6.16", 669 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", 670 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", 671 | "requires": { 672 | "media-typer": "0.3.0", 673 | "mime-types": "~2.1.18" 674 | } 675 | }, 676 | "unix-dgram": { 677 | "version": "2.0.2", 678 | "resolved": "https://registry.npmjs.org/unix-dgram/-/unix-dgram-2.0.2.tgz", 679 | "integrity": "sha512-QdKFZWzQ+cn9GloYcFw5Yp2DT7JyS5aAgMJPossiOwljrjQPqM8cOaJvkD+9aZhIVZ45OHonCvLWjm3l8fSNoA==", 680 | "requires": { 681 | "bindings": "^1.3.0", 682 | "nan": "^2.10.0" 683 | } 684 | }, 685 | "unpipe": { 686 | "version": "1.0.0", 687 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 688 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 689 | }, 690 | "utils-merge": { 691 | "version": "1.0.1", 692 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 693 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 694 | }, 695 | "validator": { 696 | "version": "10.4.0", 697 | "resolved": "https://registry.npmjs.org/validator/-/validator-10.4.0.tgz", 698 | "integrity": "sha512-Q/wBy3LB1uOyssgNlXSRmaf22NxjvDNZM2MtIQ4jaEOAB61xsh1TQxsq1CgzUMBV1lDrVMogIh8GjG1DYW0zLg==" 699 | }, 700 | "vary": { 701 | "version": "1.1.2", 702 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 703 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 704 | } 705 | } 706 | } 707 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shadowsocks-restful-api", 3 | "version": "0.1.1", 4 | "description": "Secure, reliable, standard restful api for managing shadowsocks-libev", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Eggham Carnegie ", 10 | "license": "ISC", 11 | "dependencies": { 12 | "async-lock": "^1.1.3", 13 | "babel-polyfill": "^6.26.0", 14 | "body-parser": "^1.18.3", 15 | "debug": "^3.1.0", 16 | "dotenv": "^6.0.0", 17 | "express": "^4.16.3", 18 | "express-validator": "^5.2.0", 19 | "jsonwebtoken": "^8.3.0", 20 | "passport": "^0.4.0", 21 | "passport-jwt": "^4.0.0", 22 | "portastic": "^1.0.1", 23 | "unix-dgram": "^2.0.2", 24 | "validator": "^10.3.0" 25 | }, 26 | "repository": { 27 | "type": "git", 28 | "url": "https://github.com/Eggham/shadowsocks-restful-api.git" 29 | }, 30 | "bugs": { 31 | "url": "https://github.com/Eggham/shadowsocks-restful-api/issues" 32 | }, 33 | "homepage": "https://github.com/Eggham/shadowsocks-restful-api#readme" 34 | } 35 | -------------------------------------------------------------------------------- /supervisord.conf: -------------------------------------------------------------------------------- 1 | [supervisord] 2 | nodaemon=true 3 | logfile=/dev/null 4 | logfile_maxbytes=0 5 | 6 | [program:node] 7 | stdout_logfile=/dev/fd/1 8 | stdout_logfile_maxbytes=0 9 | redirect_stderr=true 10 | command=node app.js 11 | 12 | [program:shadowsocks] 13 | stdout_logfile=/dev/fd/1 14 | stdout_logfile_maxbytes=0 15 | redirect_stderr=true 16 | command=ss-manager -u --manager-address /tmp/shadowsocks-manager.sock --fast-open --------------------------------------------------------------------------------