├── docs ├── .nojekyll ├── admin.md ├── user.md ├── _media │ ├── home.png │ ├── alipay.jpg │ ├── favicon.png │ └── wechat.jpg ├── upgrade.md ├── donate.md ├── transfer.md ├── _coverpage.md ├── managerapi.md ├── vps.md ├── skin.md ├── _sidebar.md ├── home.md ├── install.md ├── pay.md ├── topological.md ├── ssmgrapi.md ├── index.html └── config.md ├── plugins ├── webgui │ ├── public │ │ ├── views │ │ │ ├── home │ │ │ │ ├── ref.html │ │ │ │ ├── macLogin.html │ │ │ │ ├── refInput.html │ │ │ │ ├── telegramLogin.html │ │ │ │ └── index.html │ │ │ ├── admin │ │ │ │ ├── unfinished.html │ │ │ │ ├── mailSetting.html │ │ │ │ ├── previewNotice.html │ │ │ │ ├── orderSetting.html │ │ │ │ ├── pickAccount.html │ │ │ │ ├── groupList.html │ │ │ │ ├── paymentList.html │ │ │ │ ├── notice.html │ │ │ │ ├── settings.html │ │ │ │ ├── giftcardBatchList.html │ │ │ │ ├── editRefCode.html │ │ │ │ ├── user.html │ │ │ │ ├── telegramSetting.html │ │ │ │ ├── account.html │ │ │ │ ├── addUser.html │ │ │ │ ├── refCodeList.html │ │ │ │ ├── accountSortAndFilterDialog.html │ │ │ │ ├── newNotice.html │ │ │ │ ├── editNotice.html │ │ │ │ ├── changePassword.html │ │ │ │ └── userSortDialog.html │ │ │ ├── skin │ │ │ │ ├── fs_zelda │ │ │ │ │ └── zelda.jpg │ │ │ │ ├── fs_dinosaur │ │ │ │ │ ├── assets │ │ │ │ │ │ ├── offline-sprite-1x.png │ │ │ │ │ │ ├── offline-sprite-2x.png │ │ │ │ │ │ ├── default_100_percent │ │ │ │ │ │ │ ├── 100-disabled.png │ │ │ │ │ │ │ ├── 100-error-offline.png │ │ │ │ │ │ │ └── 100-offline-sprite.png │ │ │ │ │ │ └── default_200_percent │ │ │ │ │ │ │ ├── 200-disabled.png │ │ │ │ │ │ │ ├── 200-error-offline.png │ │ │ │ │ │ │ └── 200-offline-sprite.png │ │ │ │ │ └── README.md │ │ │ │ ├── bing.html │ │ │ │ └── default.html │ │ │ ├── user │ │ │ │ ├── macAddress.html │ │ │ │ ├── qrcodeDialog.html │ │ │ │ ├── order.html │ │ │ │ ├── telegram.html │ │ │ │ └── changePassword.html │ │ │ └── dialog │ │ │ │ ├── autopop.html │ │ │ │ ├── showWireGuardConfig.html │ │ │ │ ├── language.html │ │ │ │ ├── alert.html │ │ │ │ ├── serverChart.html │ │ │ │ ├── addMacAccount.html │ │ │ │ ├── setUserGroup.html │ │ │ │ ├── confirm.html │ │ │ │ ├── subscribe.html │ │ │ │ ├── setEmail.html │ │ │ │ ├── email.html │ │ │ │ ├── editUserComment.html │ │ │ │ └── payByGiftCard.html │ │ ├── translate │ │ │ ├── zh-CN.js │ │ │ └── index.js │ │ ├── app.js │ │ ├── configs │ │ │ ├── index.js │ │ │ ├── sceProvider.js │ │ │ ├── urlRouter.js │ │ │ ├── themingProvider.js │ │ │ └── auth.js │ │ ├── dialogs │ │ │ ├── index.js │ │ │ ├── serverChart.js │ │ │ ├── markdown.js │ │ │ ├── qrcode.js │ │ │ ├── addGiftCardBatch.js │ │ │ ├── editUserComment.js │ │ │ ├── autopop.js │ │ │ ├── alert.js │ │ │ ├── language.js │ │ │ ├── setUserGroup.js │ │ │ ├── changePassword.js │ │ │ ├── user.js │ │ │ ├── addMacAccount.js │ │ │ ├── confirm.js │ │ │ ├── ban.js │ │ │ └── email.js │ │ ├── filters │ │ │ ├── index.js │ │ │ ├── substr.js │ │ │ ├── mac.js │ │ │ ├── giftcard.js │ │ │ ├── ban.js │ │ │ └── orderStatus.js │ │ ├── routes │ │ │ ├── index.js │ │ │ ├── adminUser.js │ │ │ ├── adminServer.js │ │ │ ├── adminAccount.js │ │ │ ├── admin.js │ │ │ ├── user.js │ │ │ └── home.js │ │ ├── controllers │ │ │ └── index.js │ │ ├── services │ │ │ ├── configService.js │ │ │ ├── websocketService.js │ │ │ └── preloadService.js │ │ ├── directives │ │ │ └── focusMe.js │ │ ├── index.js │ │ └── styles │ │ │ └── default.css │ ├── dependence.js │ ├── libs │ │ ├── favicon.png │ │ ├── MaterialIcons-Regular.eot │ │ ├── MaterialIcons-Regular.ttf │ │ ├── MaterialIcons-Regular.woff │ │ ├── MaterialIcons-Regular.woff2 │ │ ├── forkme_right_white_ffffff.png │ │ ├── ngclipboard.min.js │ │ └── style.css │ ├── screenshot │ │ ├── 01.png │ │ ├── 02.png │ │ ├── 03.png │ │ ├── 04.png │ │ └── 05.png │ ├── db │ │ ├── setting.js │ │ ├── push.js │ │ └── notice.js │ ├── views │ │ ├── manifest.js │ │ └── error.html │ └── server │ │ └── adminGroup.js ├── giftcard │ ├── README.md │ └── db │ │ └── giftcard.js ├── cli │ ├── screenshot │ │ ├── cli01.png │ │ └── cli02.png │ ├── index.js │ ├── menu │ │ ├── addPort.js │ │ ├── main.js │ │ ├── flow.js │ │ └── addServer.js │ └── README.md ├── telegram │ ├── screenshot │ │ ├── telegram01.png │ │ └── telegram02.png │ ├── db │ │ ├── telegram.js │ │ ├── flow.js │ │ └── server.js │ ├── managerAddress.js │ ├── help.js │ ├── serverManager.js │ ├── README.md │ ├── auth.js │ └── flow.js ├── flowSaver │ ├── README.md │ └── db │ │ ├── saveFlow.js │ │ ├── saveFlow5min.js │ │ ├── saveFlowDay.js │ │ ├── saveFlowHour.js │ │ └── server.js ├── email │ ├── README.md │ └── db │ │ └── email.js ├── webgui_telegram │ ├── db │ │ └── webgui_telegram.js │ ├── admin.js │ ├── help.js │ └── flow.js ├── webgui_order │ ├── flowPack.js │ └── db │ │ └── webgui_flow_pack.js ├── webgui_ref │ └── db │ │ ├── webgui_ref.js │ │ ├── webgui_ref_code.js │ │ └── webgui_ref_time.js ├── freeAccount │ ├── db │ │ └── freeAccount.js │ └── README.md ├── macAccount │ └── db │ │ └── macAccount.js ├── webgui_autoban │ └── README.md ├── alipay │ └── db │ │ └── alipay.js ├── paypal │ └── db │ │ └── paypal.js ├── account │ └── db │ │ ├── accountFlow.js │ │ └── account.js ├── user │ └── db │ │ └── user.js └── group │ ├── db │ └── group.js │ └── index.js ├── .gitattributes ├── wikiImage ├── signup.png ├── addServer.png ├── addAccount.png ├── homeScreenChrome.jpg └── homeScreenSafari.jpg ├── bin └── ssmgr ├── config └── default.yml ├── init ├── utils.js ├── loadModels.js ├── loadServices.js ├── cron.js ├── knex.js ├── moveConfigFile.js ├── runShadowsocks.js ├── log.js ├── loadPlugins.js └── checkConfig.js ├── .eslintrc.json ├── models ├── account.js ├── command.js └── flow.js ├── docker ├── ubuntu │ └── Dockerfile └── alpine │ └── Dockerfile ├── .github └── issue_template.md ├── server.js ├── .gitignore ├── .npmignore └── services └── config.js /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /docs/admin.md: -------------------------------------------------------------------------------- 1 | # 管理员 -------------------------------------------------------------------------------- /docs/user.md: -------------------------------------------------------------------------------- 1 | # 普通用户 -------------------------------------------------------------------------------- /plugins/webgui/public/views/home/ref.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plugins/webgui/public/views/home/macLogin.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plugins/webgui/public/views/home/refInput.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plugins/webgui/public/views/home/telegramLogin.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /plugins/webgui/public/translate/zh-CN.js: -------------------------------------------------------------------------------- 1 | module.exports = {}; -------------------------------------------------------------------------------- /plugins/webgui/public/views/admin/unfinished.html: -------------------------------------------------------------------------------- 1 |
--------------------------------------------------------------------------------
/init/moveConfigFile.js:
--------------------------------------------------------------------------------
1 | const os = require('os');
2 | const fs = require('fs');
3 | const fse = require('fs-extra');
4 | const path = require('path');
5 | const ssmgrPath = path.resolve(os.homedir(), './.ssmgr/');
6 |
7 | const configFiles = [
8 | 'default.yml',
9 | ];
10 |
11 | const log4js = require('log4js');
12 | const logger = log4js.getLogger('system');
13 |
14 | try {
15 | fs.statSync(ssmgrPath);
16 | } catch(err) {
17 | logger.info('~/.ssmgr/ not found, make dir for it.');
18 | fs.mkdirSync(ssmgrPath);
19 | }
20 | configFiles.forEach(configFile => {
21 | try {
22 | fs.statSync(path.resolve(ssmgrPath, configFile));
23 | } catch(err) {
24 | logger.info(`~/.ssmgr/${ configFile } not found, make file for it.`);
25 | fse.copySync(path.resolve(`./config/${ configFile }`), path.resolve(ssmgrPath, configFile));
26 | }
27 | });
28 |
--------------------------------------------------------------------------------
/plugins/webgui/db/notice.js:
--------------------------------------------------------------------------------
1 | const knex = appRequire('init/knex').knex;
2 | const tableName = 'notice';
3 |
4 | const createTable = async() => {
5 | const exist = await knex.schema.hasTable(tableName);
6 | if(exist) {
7 | const hasAutopop = await knex.schema.hasColumn(tableName, 'autopop');
8 | if(!hasAutopop) {
9 | await knex.schema.table(tableName, function(table) {
10 | table.integer('autopop').defaultTo(0);
11 | });
12 | }
13 | return;
14 | }
15 | return knex.schema.createTable(tableName, function(table) {
16 | table.increments('id').primary();
17 | table.string('title');
18 | table.string('content', 16384);
19 | table.bigInteger('time');
20 | table.integer('group').defaultTo(0);
21 | table.integer('autopop').defaultTo(0);
22 | });
23 | };
24 |
25 | exports.createTable = createTable;
26 |
--------------------------------------------------------------------------------
/plugins/webgui/public/views/dialog/showWireGuardConfig.html:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/plugins/webgui/public/routes/admin.js:
--------------------------------------------------------------------------------
1 | const app = angular.module('app');
2 | const window = require('window');
3 | const cdn = window.cdn || '';
4 |
5 | app.config(['$stateProvider', $stateProvider => {
6 | $stateProvider
7 | .state('admin', {
8 | url: '/admin',
9 | abstract: true,
10 | templateUrl: `${ cdn }/public/views/admin/admin.html`,
11 | resolve: {
12 | myConfig: ['$http', 'configManager', ($http, configManager) => {
13 | if(configManager.getConfig().version) { return; }
14 | return $http.get('/api/home/login').then(success => {
15 | configManager.setConfig(success.data);
16 | });
17 | }]
18 | },
19 | })
20 | .state('admin.index', {
21 | url: '/index',
22 | controller: 'AdminIndexController',
23 | templateUrl: `${ cdn }/public/views/admin/index.html`,
24 | })
25 | .state('admin.pay', {
26 | url: '/pay',
27 | controller: 'AdminPayController',
28 | templateUrl: `${ cdn }/public/views/admin/pay.html`,
29 | })
30 | .state('admin.unfinished', {
31 | url: '/unfinished',
32 | templateUrl: `${ cdn }/public/views/admin/unfinished.html`,
33 | });
34 | }
35 | ]);
36 |
--------------------------------------------------------------------------------
/plugins/cli/menu/addPort.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const manager = appRequire('services/manager');
4 | const index = appRequire('plugins/cli/index');
5 |
6 | const inquirer = require('inquirer');
7 |
8 | const menu = [{
9 | type: 'input',
10 | name: 'port',
11 | message: 'Enter port:',
12 | validate: function (value) {
13 | if(Number.isNaN(+value)) {
14 | return 'Please enter a valid port number.';
15 | } else if (+value <= 0 || +value >= 65536) {
16 | return 'Port number must between 1 to 65535.';
17 | } else {
18 | return true;
19 | }
20 | },
21 | }, {
22 | type: 'input',
23 | name: 'password',
24 | message: 'Enter password:',
25 | validate: function (value) {
26 | if(value === '') {
27 | return 'You can not set an empty password.';
28 | } else {
29 | return true;
30 | }
31 | },
32 | }];
33 |
34 | const add = async () => {
35 | try {
36 | const addPort = await inquirer.prompt(menu);
37 | await manager.send({
38 | command: 'add',
39 | port: +addPort.port,
40 | password: addPort.password,
41 | }, index.getManagerAddress());
42 | return;
43 | } catch(err) {
44 | return Promise.reject(err);
45 | }
46 | };
47 |
48 | exports.add = add;
49 |
--------------------------------------------------------------------------------
/plugins/account/db/accountFlow.js:
--------------------------------------------------------------------------------
1 | const knex = appRequire('init/knex').knex;
2 | const tableName = 'account_flow';
3 |
4 | const createTable = async() => {
5 | const exist = await knex.schema.hasTable(tableName);
6 | if(exist) {
7 | const hasStatus = await knex.schema.hasColumn(tableName, 'status');
8 | if(!hasStatus) {
9 | await knex.schema.table(tableName, function(table) {
10 | table.string('status').defaultTo('checked');
11 | });
12 | }
13 | const hasAutobanTime = await knex.schema.hasColumn(tableName, 'autobanTime');
14 | if(!hasAutobanTime) {
15 | await knex.schema.table(tableName, function(table) {
16 | table.bigInteger('autobanTime');
17 | });
18 | }
19 | return;
20 | }
21 | return knex.schema.createTable(tableName, function(table) {
22 | table.increments('id');
23 | table.integer('serverId');
24 | table.integer('accountId');
25 | table.integer('port');
26 | table.bigInteger('updateTime');
27 | table.bigInteger('checkTime');
28 | table.bigInteger('nextCheckTime');
29 | table.bigInteger('autobanTime');
30 | table.bigInteger('flow').defaultTo(0);
31 | table.string('status').defaultTo('checked');
32 | });
33 | };
34 |
35 | exports.createTable = createTable;
36 |
--------------------------------------------------------------------------------
/plugins/webgui/public/directives/focusMe.js:
--------------------------------------------------------------------------------
1 | const app = angular.module('app');
2 |
3 | app.directive('focusMe', ['$timeout', $timeout => {
4 | return {
5 | restrict: 'A',
6 | link: ($scope, $element) => {
7 | $timeout(() => {
8 | $element[0].focus();
9 | });
10 | }
11 | };
12 | }]);
13 |
14 | app.directive('ga', () => {
15 | return {
16 | restrict: 'E',
17 | scope: {
18 | adClient: '@',
19 | adSlot: '@',
20 | adFormat: '@',
21 | },
22 | template: `
23 |
24 |
25 |
31 |
32 | `,
33 | controller: ['$scope', '$timeout', ($scope, $timeout) => {
34 | $scope.show = Math.random() >= 0.95;
35 | if($scope.show) {
36 | $timeout(function () {
37 | (window.adsbygoogle = window.adsbygoogle || []).push({});
38 | });
39 | }
40 | }]
41 | };
42 | });
43 |
--------------------------------------------------------------------------------
/plugins/webgui/public/index.js:
--------------------------------------------------------------------------------
1 | angular.module('app', [
2 | 'ngMaterial',
3 | 'ui.router',
4 | 'ngMessages',
5 | 'ja.qr',
6 | 'chart.js',
7 | 'angularMoment',
8 | 'ngWebSocket',
9 | 'ngStorage',
10 | 'angular-inview',
11 | 'hc.marked',
12 | 'pascalprecht.translate',
13 | 'ngclipboard',
14 | ]);
15 |
16 | const window = require('window');
17 | angular.element(() => {
18 | $.get(window.api + '/api/home/login').then(success => {
19 | window.ssmgrConfig = success;
20 |
21 | require('./directives/focusMe');
22 |
23 | require('./services/preloadService.js');
24 | require('./services/adminService.js');
25 | require('./services/homeService.js');
26 | require('./services/userService.js');
27 | require('./services/configService.js');
28 | // require('./services/websocketService.js');
29 |
30 | require('./configs/index.js');
31 | require('./controllers/index.js');
32 | require('./dialogs/index.js');
33 | require('./filters/index.js');
34 | require('./translate/index.js');
35 | require('./routes/index.js');
36 |
37 | angular.bootstrap(document, ['app']);
38 | }).catch(err => {
39 | let time = 5000;
40 | if(err.status === 403) { time = 1500; }
41 | setTimeout(() => { location.reload(); }, time);
42 | });
43 | });
--------------------------------------------------------------------------------
/plugins/telegram/db/server.js:
--------------------------------------------------------------------------------
1 | const knex = appRequire('init/knex').knex;
2 | const tableName = 'server';
3 | const config = appRequire('services/config').all();
4 | const manager = appRequire('services/manager');
5 |
6 | const createTable = async () => {
7 | await knex.schema.createTable(tableName, function(table) {
8 | table.increments('id');
9 | table.string('name');
10 | table.string('host');
11 | table.integer('port');
12 | table.string('password');
13 | table.string('method').defaultTo('aes-256-cfb');
14 | });
15 | const list = await knex('server').select(['name', 'host', 'port', 'password']);
16 | if(list.length === 0) {
17 | const host = config.manager.address.split(':')[0];
18 | const port = +config.manager.address.split(':')[1];
19 | const password = config.manager.password;
20 | await manager.send({
21 | command: 'version'
22 | }, {
23 | host,
24 | port,
25 | password,
26 | }).catch(() => {
27 | logger.error(`connect to server ${ password }@${ host }:${ port } fail.`);
28 | process.exit(1);
29 | });
30 | await knex('server').insert({
31 | name: 'default',
32 | host,
33 | port,
34 | password,
35 | });
36 | }
37 | return;
38 | };
39 |
40 | exports.createTable = createTable;
41 |
--------------------------------------------------------------------------------
/plugins/user/db/user.js:
--------------------------------------------------------------------------------
1 | const knex = appRequire('init/knex').knex;
2 | const tableName = 'user';
3 |
4 | const createTable = async() => {
5 | const exist = await knex.schema.hasTable(tableName);
6 | if(exist) {
7 | const hasColumnGroup = await knex.schema.hasColumn(tableName, 'group');
8 | if(!hasColumnGroup) {
9 | await knex.schema.table(tableName, function(table) {
10 | table.integer('group').defaultTo(0);
11 | });
12 | }
13 | const hasComment = await knex.schema.hasColumn(tableName, 'comment');
14 | if(!hasComment) {
15 | await knex.schema.table(tableName, function(table) {
16 | table.string('comment').defaultTo('');
17 | });
18 | }
19 | return;
20 | }
21 | return knex.schema.createTable(tableName, function(table) {
22 | table.increments('id').primary();
23 | table.string('username').unique();
24 | table.string('email');
25 | table.string('telegram');
26 | table.string('password');
27 | table.string('type');
28 | table.bigInteger('createTime');
29 | table.bigInteger('lastLogin');
30 | table.string('resetPasswordId');
31 | table.bigInteger('resetPasswordTime');
32 | table.integer('group').defaultTo(0);
33 | table.string('comment').defaultTo('');
34 | });
35 | };
36 |
37 | exports.createTable = createTable;
38 |
--------------------------------------------------------------------------------
/plugins/webgui/public/dialogs/serverChart.js:
--------------------------------------------------------------------------------
1 | const app = angular.module('app');
2 | const window = require('window');
3 | const cdn = window.cdn || '';
4 |
5 | app.factory('serverChartDialog' , [ '$mdDialog', $mdDialog => {
6 | const publicInfo = {};
7 | const hide = () => {
8 | return $mdDialog.hide()
9 | .then(success => {
10 | dialogPromise = null;
11 | return;
12 | }).catch(err => {
13 | dialogPromise = null;
14 | return;
15 | });
16 | };
17 | publicInfo.hide = hide;
18 | let dialogPromise = null;
19 | const isDialogShow = () => {
20 | if(dialogPromise && !dialogPromise.$$state.status) {
21 | return true;
22 | }
23 | return false;
24 | };
25 | const dialog = {
26 | templateUrl: `${ cdn }/public/views/dialog/serverChart.html`,
27 | escapeToClose: false,
28 | locals: { bind: publicInfo },
29 | bindToController: true,
30 | controller: ['$scope', 'bind', function($scope, bind) {
31 | $scope.publicInfo = bind;
32 | }],
33 | clickOutsideToClose: true,
34 | };
35 | const show = serverChart => {
36 | if(isDialogShow()) {
37 | return dialogPromise;
38 | }
39 | publicInfo.serverChart = serverChart;
40 | dialogPromise = $mdDialog.show(dialog);
41 | return dialogPromise;
42 | };
43 | return {
44 | show,
45 | hide,
46 | };
47 | }]);
--------------------------------------------------------------------------------
/plugins/account/db/account.js:
--------------------------------------------------------------------------------
1 | const knex = appRequire('init/knex').knex;
2 | const tableName = 'account_plugin';
3 |
4 | const createTable = async() => {
5 | const exist = await knex.schema.hasTable(tableName);
6 | if(exist) {
7 | const hasKey = await knex.schema.hasColumn(tableName, 'key');
8 | if(!hasKey) {
9 | await knex.schema.table(tableName, function(table) {
10 | table.string('key');
11 | });
12 | }
13 | const results = await knex(tableName).whereNull('orderId');
14 | for(const result of results) {
15 | await knex(tableName).update({ orderId: result.type === 1 ? 0 : result.type }).where({ id: result.id });
16 | }
17 | return;
18 | }
19 | return knex.schema.createTable(tableName, function(table) {
20 | table.increments('id');
21 | table.integer('type');
22 | table.integer('orderId');
23 | table.integer('userId');
24 | table.string('server');
25 | table.integer('port').unique();
26 | table.string('password');
27 | table.string('key');
28 | table.string('data');
29 | table.string('subscribe');
30 | table.integer('status');
31 | table.integer('autoRemove').defaultTo(0);
32 | table.bigInteger('autoRemoveDelay').defaultTo(0);
33 | table.integer('multiServerFlow').defaultTo(0);
34 | table.integer('active').defaultTo(1);
35 | });
36 | };
37 |
38 | exports.createTable = createTable;
39 |
--------------------------------------------------------------------------------
/docs/ssmgrapi.md:
--------------------------------------------------------------------------------
1 | # ssmgr API
2 |
3 | ssmgr 之间采用 TCP socket 的方式通讯,接口协议如下:
4 |
5 | 发送:`[2字节 消息长度][6字节时间戳][指令][4字节 校验码]`
6 |
7 | 返回:`[2字节 消息长度[内容]`
8 |
9 | * 列出服务器上的端口和密码
10 |
11 | ```
12 | {
13 | command: 'list'
14 | }
15 | [
16 | { port: 1234, password: '5678'},
17 | { port: 1235, password: '5678'}
18 | ]
19 | ```
20 |
21 | * 添加端口
22 |
23 | ```
24 | {
25 | command: 'add',
26 | port: 1234,
27 | password: 'qwer'
28 | }
29 | {
30 | port: 1234,
31 | password: 'qwer'
32 | }
33 | ```
34 |
35 | * 删除端口
36 |
37 | ```
38 | {
39 | command: 'del',
40 | port: 1234
41 | }
42 | {
43 | port: 1234
44 | }
45 | ```
46 |
47 | * 修改密码
48 |
49 | ```
50 | {
51 | command: 'pwd'
52 | port: 1234,
53 | password: 'asdfgh'
54 | }
55 | {
56 | port: 1234,
57 | password: 'asdfgh'
58 | }
59 | ```
60 |
61 | * 查询流量
62 |
63 | ```
64 | {
65 | command: 'flow',
66 | port: 1234,
67 | options: {
68 | startTime: 1489137503258,
69 | endTime: 1489137603258,
70 | clear: true
71 | }
72 | }
73 | [
74 | { port: 1234, sumFlow: 1234 },
75 | { port: 1235, sumFlow: 1234 }
76 | ]
77 | ```
78 |
79 | * 查询版本号
80 |
81 | ```
82 | {
83 | command: 'version'
84 | }
85 | {
86 | version: 0.9.0
87 | }
88 | ```
89 |
90 | * 查询客户端连接IP
91 |
92 | ```
93 | {
94 | command: 'ip',
95 | port: 1234
96 | }
97 | [
98 | '1.1.1.1',
99 | '2.2.2.2'
100 | ]
101 | ```
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |