瀏覽代碼

WebApi Bate & more

1. 完善 laravel5.8框架文件;
2. 按照VentPanel开发的WebApi Bate;
3. bug修复与优化
4. WebApi 授权相关界面;
兔姬桑 4 年之前
父節點
當前提交
265fced5e2
共有 88 個文件被更改,包括 1759 次插入658 次删除
  1. 9 2
      .env.example
  2. 39 22
      app/Http/Controllers/Admin/RuleController.php
  3. 5 10
      app/Http/Controllers/AdminController.php
  4. 333 0
      app/Http/Controllers/Api/V2Ray/V1Controller.php
  5. 1 1
      app/Http/Controllers/Controller.php
  6. 124 79
      app/Http/Controllers/NodeController.php
  7. 2 1
      app/Http/Controllers/PaymentController.php
  8. 1 1
      app/Http/Controllers/User/SubscribeController.php
  9. 1 1
      app/Http/Controllers/UserController.php
  10. 22 0
      app/Http/Kernel.php
  11. 19 0
      app/Http/Middleware/Authenticate.php
  12. 2 1
      app/Http/Middleware/RedirectIfAuthenticated.php
  13. 2 2
      app/Http/Middleware/TrustProxies.php
  14. 7 0
      app/Http/Middleware/VerifyCsrfToken.php
  15. 41 16
      app/Http/Middleware/WebApi.php
  16. 1 1
      app/Models/Article.php
  17. 1 1
      app/Models/Goods.php
  18. 13 15
      app/Models/Invite.php
  19. 36 0
      app/Models/NodeAuth.php
  20. 31 0
      app/Models/NodeCertificate.php
  21. 2 2
      app/Models/NotificationLog.php
  22. 22 0
      app/Models/Rule.php
  23. 1 1
      app/Models/RuleGroup.php
  24. 64 43
      app/Models/SsNode.php
  25. 11 10
      app/Models/SsNodeIp.php
  26. 1 2
      app/Models/UserTrafficLog.php
  27. 12 11
      app/Providers/AppServiceProvider.php
  28. 1 2
      app/Providers/AuthServiceProvider.php
  29. 1 1
      bootstrap/app.php
  30. 82 78
      composer.json
  31. 81 8
      composer.lock
  32. 20 2
      config/app.php
  33. 1 0
      config/auth.php
  34. 1 1
      config/broadcasting.php
  35. 17 8
      config/cache.php
  36. 2 2
      config/captcha.php
  37. 33 6
      config/database.php
  38. 1 1
      config/domains.php
  39. 1 1
      config/filesystems.php
  40. 1 1
      config/hashing.php
  41. 15 2
      config/logging.php
  42. 9 9
      config/mail.php
  43. 7 5
      config/permission.php
  44. 7 6
      config/queue.php
  45. 11 12
      config/services.php
  46. 15 13
      config/session.php
  47. 4 1
      config/view.php
  48. 1 0
      database/.gitignore
  49. 7 3
      database/factories/UserFactory.php
  50. 9 6
      package.json
  51. 6 6
      phpunit.xml
  52. 二進制
      public/assets/images/noimage.png
  53. 二進制
      public/assets/images/payment/alipay.png
  54. 二進制
      public/assets/images/payment/pp-logo-150px.png
  55. 二進制
      public/assets/images/payment/wechat.png
  56. 5 0
      public/web.config
  57. 0 23
      resources/assets/js/components/Example.vue
  58. 0 23
      resources/assets/js/components/ExampleComponent.vue
  59. 14 3
      resources/js/app.js
  60. 3 18
      resources/js/bootstrap.js
  61. 23 0
      resources/js/components/ExampleComponent.vue
  62. 2 2
      resources/sass/_variables.scss
  63. 2 5
      resources/sass/app.scss
  64. 1 1
      resources/views/admin/article/articleList.blade.php
  65. 39 0
      resources/views/admin/config/system.blade.php
  66. 1 1
      resources/views/admin/coupon/addCoupon.blade.php
  67. 3 4
      resources/views/admin/coupon/couponList.blade.php
  68. 35 30
      resources/views/admin/layouts.blade.php
  69. 1 2
      resources/views/admin/logs/notificationLog.blade.php
  70. 5 7
      resources/views/admin/logs/onlineIPMonitor.blade.php
  71. 280 0
      resources/views/admin/node/authList.blade.php
  72. 12 35
      resources/views/admin/node/nodeInfo.blade.php
  73. 2 2
      resources/views/admin/node/nodeList.blade.php
  74. 2 2
      resources/views/admin/rule/assignNode.blade.php
  75. 1 1
      resources/views/admin/rule/ruleGroupInfo.blade.php
  76. 1 1
      resources/views/admin/rule/ruleGroupList.blade.php
  77. 1 1
      resources/views/admin/rule/ruleList.blade.php
  78. 1 2
      resources/views/admin/subscribe/subscribeList.blade.php
  79. 38 32
      resources/views/admin/user/userList.blade.php
  80. 2 2
      resources/views/user/invoices.blade.php
  81. 3 3
      resources/views/user/referral.blade.php
  82. 20 5
      routes/api.php
  83. 2 2
      routes/channels.php
  84. 2 2
      routes/console.php
  85. 11 4
      routes/web.php
  86. 76 46
      sql/db.sql
  87. 32 0
      sql/mod/20200630.sql
  88. 3 3
      webpack.mix.js

+ 9 - 2
.env.example

@@ -1,5 +1,5 @@
 APP_DEMO=false
-APP_NAME=OtakuPanel_SSR
+APP_NAME=ProxyPanel
 APP_ENV=local
 APP_KEY=
 APP_DEBUG=false
@@ -19,9 +19,9 @@ DB_STRICT=false
 
 BROADCAST_DRIVER=redis
 CACHE_DRIVER=redis
+QUEUE_CONNECTION=redis
 SESSION_DRIVER=redis
 SESSION_LIFETIME=120
-QUEUE_DRIVER=redis
 
 REDIS_HOST=127.0.0.1
 REDIS_PASSWORD=null
@@ -33,11 +33,18 @@ MAIL_PORT=465
 MAIL_USERNAME=admin@ssrpanel.com
 MAIL_PASSWORD=password
 MAIL_ENCRYPTION=ssl
+MAIL_LOG_CHANNEL=daily
 MAIL_FROM_ADDRESS=admin@ssrpanel.com
 MAIL_FROM_NAME=SSRPanel
+
 MAILGUN_DOMAIN=
 MAILGUN_SECRET=
 
+AWS_ACCESS_KEY_ID=
+AWS_SECRET_ACCESS_KEY=
+AWS_DEFAULT_REGION=us-east-1
+AWS_BUCKET=
+
 PUSHER_APP_ID=
 PUSHER_APP_KEY=
 PUSHER_APP_SECRET=

+ 39 - 22
app/Http/Controllers/Admin/RuleController.php

@@ -78,15 +78,16 @@ class RuleController extends Controller {
 	}
 
 	// 删除审计规则
-	public function delRule($id) {
+	public function delRule(Request $request) {
+		$id = $request->input('id');
 		try{
 			Rule::query()->whereId($id)->delete();
 
 			$RuleGroupList = RuleGroup::query()->get();
 			foreach($RuleGroupList as $RuleGroup){
-				$rules = explode(', ', $RuleGroup->rules);
+				$rules = explode(',', $RuleGroup->rules);
 				if(in_array($id, $rules)){
-					$rules = implode(', ', array_diff($rules, (array) $id));
+					$rules = implode(',', array_diff($rules, (array) $id));
 					RuleGroup::query()->whereId($RuleGroup->id)->update(['rules' => $rules]);
 				}
 			}
@@ -118,7 +119,7 @@ class RuleController extends Controller {
 			$obj = new RuleGroup();
 			$obj->name = $request->input('name');
 			$obj->type = intval($request->input('type'));
-			$obj->rules = implode(", ", $request->input('rules'));
+			$obj->rules = implode(',', $request->input('rules'));
 			$obj->save();
 
 			if($obj->id){
@@ -138,10 +139,9 @@ class RuleController extends Controller {
 		$id = $request->input('id');
 		if($request->isMethod('POST')){
 			$validator = Validator::make($request->all(), [
-				'id'    => 'required',
-				'name'  => 'required',
-				'type'  => 'required|boolean',
-				'rules' => 'required',
+				'id'   => 'required',
+				'name' => 'required',
+				'type' => 'required|boolean'
 			]);
 
 			if($validator->fails()){
@@ -162,8 +162,15 @@ class RuleController extends Controller {
 			if($ruleGroup->type != $type){
 				$data['type'] = $type;
 			}
-			if($ruleGroup->rules != $rules){
-				$data['rules'] = implode(", ", $rules);
+			if($rules){
+				$ruleStr = implode(',', $rules);
+				if($ruleGroup->rules != $ruleStr){
+					$data['rules'] = $ruleStr;
+				}else{
+					return Redirect::back()->with('successMsg', '检测为未修改,无变动!');
+				}
+			}elseif(isset($ruleGroup->rules)){
+				$data['rules'] = $rules;
 			}
 			$ret = RuleGroup::query()->whereId($id)->update($data);
 			if($ret){
@@ -183,7 +190,8 @@ class RuleController extends Controller {
 	}
 
 	// 删除审计规则分组
-	public function delRuleGroup($id) {
+	public function delRuleGroup(Request $request) {
+		$id = $request->input('id');
 		$ruleGroup = RuleGroup::query()->whereId($id)->get();
 		if(!$ruleGroup){
 			return Response::json(['status' => 'fail', 'message' => '删除失败,未找到审计规则分组']);
@@ -204,8 +212,7 @@ class RuleController extends Controller {
 		if($request->isMethod('POST')){
 			$nodes = $request->input('nodes');
 			$validator = Validator::make($request->all(), [
-				'id'    => 'required',
-				'nodes' => 'required',
+				'id' => 'required',
 			]);
 
 			if($validator->fails()){
@@ -216,18 +223,28 @@ class RuleController extends Controller {
 			if(!$ruleGroup){
 				return Redirect::back()->withInput()->withErrors('未找到审计规则分组!');
 			}
+
 			try{
-				if($ruleGroup->nodes != $nodes){
-					RuleGroup::query()->whereId($id)->update(['nodes' => implode(", ", $nodes)]);
+				if($nodes){
+					$nodeStr = implode(',', $nodes);
+					// 无变动 不改动
+					if($ruleGroup->nodes == $nodeStr){
+						return Redirect::back()->with('successMsg', '检测为未修改,无变动!');
+					}
+					RuleGroup::query()->whereId($id)->update(['nodes' => $nodeStr]);
+					RuleGroupNode::query()->whereRuleGroupId($id)->delete();
+
+					foreach($nodes as $nodeId){
+						$obj = new RuleGroupNode();
+						$obj->rule_group_id = $id;
+						$obj->node_id = $nodeId;
+						$obj->save();
+					}
+				}else{
+					RuleGroup::query()->whereId($id)->update(['nodes' => $nodes]);
+					RuleGroupNode::query()->whereRuleGroupId($id)->delete();
 				}
-				RuleGroupNode::query()->whereRuleGroupId($id)->delete();
 
-				foreach($nodes as $nodeId){
-					$obj = new RuleGroupNode();
-					$obj->rule_group_id = $id;
-					$obj->node_id = $nodeId;
-					$obj->save();
-				}
 			}catch(Exception $e){
 				return Redirect::back()->withInput()->withErrors($e->getMessage());
 			}

+ 5 - 10
app/Http/Controllers/AdminController.php

@@ -664,7 +664,7 @@ class AdminController extends Controller {
 
 			$node = SsNode::query()->whereId($node_id)->first();
 			$proxyType = $node->type == 1? ($node->compatible? 'SS' : 'SSR') : 'V2Ray';
-			$data = $this->getNodeInfo($id, $node->id, $infoType != 'text'? 0 : 1);
+			$data = $this->getUserNodeInfo($id, $node->id, $infoType != 'text'? 0 : 1);
 
 			return Response::json(['status' => 'success', 'data' => $data, 'title' => $proxyType]);
 
@@ -1635,10 +1635,7 @@ EOF;
 		$nodeId = $request->input('nodeId');
 		$userId = $request->input('id');
 
-		$query = SsNodeIp::query()
-		                 ->with(['node', 'user'])
-		                 ->whereType('tcp')
-		                 ->where('created_at', '>=', strtotime("-120 seconds"));
+		$query = SsNodeIp::query()->with(['node', 'user'])->where('created_at', '>=', strtotime("-120 seconds"));
 
 		if(isset($ip)){
 			$query->whereIp($ip);
@@ -1668,14 +1665,12 @@ EOF;
 			});
 		}
 
-		$list = $query->groupBy('port')->orderByDesc('id');
-
+		$list = $query->groupBy('user_id','node_id')->orderByDesc('id');
 		foreach($list as $vo){
 			// 跳过上报多IP的
-			if(strpos($vo->ip, ',') == true){
+			if(strpos($vo->ip, ',') == true || $vo->ip == null){
 				continue;
 			}
-
 			$ipInfo = QQWry::ip($vo->ip);
 			if(isset($ipInfo['error'])){
 				// 用IPIP的库再试一下
@@ -1690,7 +1685,7 @@ EOF;
 			$vo->ipInfo = $ipInfo['country'].' '.$ipInfo['province'].' '.$ipInfo['city'];
 		}
 
-		$view['list'] = $list->paginate(20)->appends($request->except('page'));
+		$view['list'] = $list->paginate(20)->appends($request->except('page'));;
 		$view['nodeList'] = SsNode::query()->whereStatus(1)->orderByDesc('sort')->orderByDesc('id')->get();
 
 		return Response::view('admin.logs.onlineIPMonitor', $view);

+ 333 - 0
app/Http/Controllers/Api/V2Ray/V1Controller.php

@@ -0,0 +1,333 @@
+<?php
+
+namespace App\Http\Controllers\Api\V2Ray;
+
+use App\Components\Helpers;
+use App\Http\Controllers\Controller;
+use App\Models\NodeCertificate;
+use App\Models\Rule;
+use App\Models\RuleGroup;
+use App\Models\RuleGroupNode;
+use App\Models\RuleLog;
+use App\Models\SsNode;
+use App\Models\SsNodeInfo;
+use App\Models\SsNodeIp;
+use App\Models\SsNodeOnlineLog;
+use App\Models\User;
+use App\Models\UserTrafficLog;
+use Illuminate\Http\Request;
+use Response;
+
+class V1Controller extends Controller {
+	// 获取节点信息
+	public function getNodeInfo($id) {
+		$node = SsNode::query()->whereId($id)->first();
+		$nodeTls = NodeCertificate::query()->whereId($node->server)->first();
+		return Response::json([
+			'status'  => 'success',
+			'code'    => 200,
+			'data'    => [
+				'id'              => $node->id,
+				'is_udp'          => $node->is_udp,
+				'client_limit'    => $node->client_limit,
+				'push_port'       => $node->push_port,
+				'secret'          => $node->auth->secret,
+				'key'             => $nodeTls? $nodeTls->key : '',
+				'pem'             => $nodeTls? $nodeTls->pem : '',
+				'v2_license'      => Helpers::systemConfig()['v2ray_license'],
+				'v2_alter_id'     => $node->v2_alter_id,
+				'v2_port'         => $node->v2_port,
+				'v2_method'       => $node->v2_method,
+				'v2_net'          => $node->v2_net,
+				'v2_type'         => $node->v2_type,
+				'v2_host'         => $node->v2_host,
+				'v2_path'         => $node->v2_path,
+				'v2_tls'          => $node->v2_tls,
+				'v2_tls_provider' => $node->v2_tls_provider,
+			],
+			'message' => '获取节点信息成功'
+		]);
+	}
+
+	// 上报节点心跳信息
+	public function setNodeStatus(Request $request, $id) {
+		$cpu = intval($request->input('cpu')) / 100;
+		$mem = intval($request->input('mem')) / 100;
+		$disk = intval($request->input('disk')) / 100;
+
+		if(is_null($request->input('uptime'))){
+			return Response::json([
+				'status'  => 'fail',
+				'code'    => 400,
+				'data'    => '',
+				'message' => '上报节点心跳信息失败,请检查字段'
+			]);
+		}
+
+		$obj = new SsNodeInfo();
+		$obj->node_id = $id;
+		$obj->uptime = intval($request->input('uptime'));
+		//$obj->load = $request->input('load');
+		$obj->load = implode(' ', [$cpu, $mem, $disk]);
+		$obj->log_time = time();
+		$obj->save();
+
+		if($obj->id){
+			return Response::json([
+				'status'  => 'success',
+				'code'    => 200,
+				'data'    => '',
+				'message' => '上报节点心跳信息成功'
+			]);
+		}
+
+		return Response::json([
+			'status'  => 'fail',
+			'code'    => 400,
+			'data'    => '',
+			'message' => '上报节点心跳信息失败,请检查字段'
+		]);
+	}
+
+	// 上报节点在线人数
+	public function setNodeOnline(Request $request, $id) {
+		$inputArray = $request->all();
+		$onlineCount = 0;
+		foreach($inputArray as $input){
+			if(!array_key_exists('ip', $input) || !array_key_exists('uid', $input)){
+				return Response::json([
+					'status'  => 'fail',
+					'code'    => 400,
+					'data'    => '',
+					'message' => '上报节点在线情况失败,请检查字段'
+				]);
+			}elseif(!isset($input['ip']) || !isset($input['uid'])){
+				return Response::json([
+					'status'  => 'fail',
+					'code'    => 400,
+					'data'    => '',
+					'message' => '上报节点在线情况失败,请检查字段'
+				]);
+			}
+
+			$obj = new SsNodeIp();
+			$obj->node_id = $id;
+			$obj->user_id = $input['uid'];
+			$obj->ip = $input['ip'];
+			$obj->port = User::find($input['uid'])->port;
+			$obj->created_at = time();
+			$obj->save();
+
+			if(!$obj->id){
+				return Response::json([
+					'status'  => 'fail',
+					'code'    => 400,
+					'data'    => '',
+					'message' => '上报节点在线情况失败,请检查字段'
+				]);
+			}
+			$onlineCount++;
+		}
+
+		$obj = new SsNodeOnlineLog();
+		$obj->node_id = $id;
+		$obj->online_user = $onlineCount;
+		$obj->log_time = time();
+		$obj->save();
+
+		if($obj->id){
+			return Response::json([
+				'status'  => 'success',
+				'code'    => 200,
+				'data'    => '',
+				'message' => '上报节点在线情况成功'
+			]);
+		}
+
+		return Response::json([
+			'status'  => 'fail',
+			'code'    => 400,
+			'data'    => '',
+			'message' => '上报节点在线情况失败,请检查字段'
+		]);
+	}
+
+	// 获取节点可用的用户列表
+	public function getUserList(Request $request, $id) {
+		$node = SsNode::query()->whereId($id)->first();
+		$users = User::query()->where('status', '<>', -1)->whereEnable(1)->where('level', '>=', $node->level)->get();
+		$data = [];
+		foreach($users as $user){
+			$new = [
+				"uid"         => $user->id,
+				"vmess_uid"   => $user->vmess_id,
+				"speed_limit" => $user->speed_limit
+			];
+			array_push($data, $new);
+		}
+
+		if($data){
+			return Response::json([
+				'status'     => 'success',
+				'code'       => 200,
+				'data'       => $data,
+				'message'    => '获取用户列表成功',
+				'updateTime' => time()
+			]);
+		}
+
+		return Response::json([
+			'status'  => 'fail',
+			'code'    => 400,
+			'data'    => '',
+			'message' => '获取用户列表失败'
+		]);
+	}
+
+	// 上报用户流量日志
+	public function setUserTraffic(Request $request, $id) {
+		$inputArray = $request->all();
+
+		foreach($inputArray as $input){
+			if(!array_key_exists('uid', $input)){
+				return Response::json([
+					'status'  => 'fail',
+					'code'    => 400,
+					'data'    => '',
+					'message' => '上报用户流量日志失败,请检查字段'
+				]);
+			}
+
+			$rate = SsNode::find($id)->traffic_rate;
+
+			$obj = new UserTrafficLog();
+			$obj->user_id = intval($input['uid']);
+			$obj->u = intval($input['upload']) * $rate;
+			$obj->d = intval($input['download']) * $rate;
+			$obj->node_id = $id;
+			$obj->rate = $rate;
+			$obj->traffic = flowAutoShow($obj->u + $obj->d);
+			$obj->log_time = time();
+			$obj->save();
+
+			if(!$obj->id){
+				return Response::json([
+					'status'  => 'fail',
+					'code'    => 400,
+					'data'    => '',
+					'message' => '上报用户流量日志失败,请检查字段'
+				]);
+			}
+		}
+
+		return Response::json([
+			'status'  => 'success',
+			'code'    => 200,
+			'data'    => '',
+			'message' => '上报用户流量日志成功'
+		]);
+	}
+
+	// 获取节点的审计规则
+	public function getNodeRule($id) {
+		$nodeRule = RuleGroupNode::whereNodeId($id)->first();
+		$data = [];
+		//节点未设置任何审计规则
+		if($nodeRule){
+			$ruleGroup = RuleGroup::query()->whereId($nodeRule->rule_group_id)->first();
+			if($ruleGroup){
+				$rules = explode(',', $ruleGroup->rules);
+				foreach($rules as $ruleId){
+					$rule = Rule::query()->whereId($ruleId)->first();
+					if($rule){
+						$new = [
+							'id'      => $rule->id,
+							'type'    => $rule->type_api_label,
+							'pattern' => $rule->pattern
+						];
+						array_push($data, $new);
+					}
+				}
+
+				return Response::json([
+					'status'  => 'success',
+					'code'    => 200,
+					'data'    => [
+						'mode'  => $ruleGroup->type? 'reject' : 'allow',
+						'rules' => $data
+					],
+					'message' => '获取节点审计规则成功'
+				]);
+
+			}
+		}
+
+		return Response::json([
+			//放行
+			'status'  => 'success',
+			'code'    => 200,
+			'data'    => [
+				'mode'  => 'all',
+				'rules' => $data
+			],
+			'message' => '获取节点审计规则成功'
+		]);
+	}
+
+	// todo: test required
+	// 上报用户触发的审计规则记录
+	public function addRuleLog(Request $request, $id) {
+		if($request->has(['uid', 'rule_id', 'reason'])){
+			$obj = new RuleLog();
+			$obj->user_id = $request->input(['uid']);
+			$obj->node_id = $id;
+			$obj->rule_id = $request->input(['rule_id']);
+			$obj->reason = $request->input(['reason']);
+			$obj->save();
+
+			if($obj->id){
+				return Response::json([
+					'status'  => 'success',
+					'code'    => 200,
+					'data'    => '',
+					'message' => '上报用户触发审计规则记录成功'
+				]);
+			}
+		}
+
+		return Response::json([
+			'status'  => 'fail',
+			'code'    => 400,
+			'data'    => '',
+			'message' => '上报用户触发审计规则记录失败'
+		]);
+
+	}
+
+	// 上报节点伪装域名证书信息
+	public function addCertificate(Request $request, $id) {
+		if($request->has(['key', 'pem'])){
+			$node = SsNode::find($id);
+			$obj = new NodeCertificate();
+			$obj->domain = $node->server;
+			$obj->key = $request->input(['key']);
+			$obj->pem = $request->input(['pem']);
+			$obj->save();
+
+			if($obj->id){
+				return Response::json([
+					'status'  => 'success',
+					'code'    => 200,
+					'data'    => '',
+					'message' => '上报节点伪装域名证书成功'
+				]);
+			}
+		}
+		return Response::json([
+			'status'  => 'fail',
+			'code'    => 400,
+			'data'    => '',
+			'message' => '上报节点伪装域名证书失败,请检查字段'
+		]);
+	}
+}

+ 1 - 1
app/Http/Controllers/Controller.php

@@ -120,7 +120,7 @@ class Controller extends BaseController {
 	 *
 	 * @return string
 	 */
-	function getNodeInfo($uid, $nodeId, $infoType) {
+	function getUserNodeInfo($uid, $nodeId, $infoType) {
 		$user = User::whereId($uid)->first();
 		$node = SsNode::whereId($nodeId)->first();
 		$scheme = null;

+ 124 - 79
app/Http/Controllers/NodeController.php

@@ -7,6 +7,7 @@ use App\Components\NetworkDetection;
 use App\Models\Country;
 use App\Models\Label;
 use App\Models\Level;
+use App\Models\NodeAuth;
 use App\Models\SsNode;
 use App\Models\SsNodeInfo;
 use App\Models\SsNodeLabel;
@@ -67,7 +68,8 @@ class NodeController extends Controller {
 		return Response::view('admin.node.nodeList', $view);
 	}
 
-	public function checkNode($id){
+	public function checkNode(Request $request) {
+		$id = $request->input('id');
 		$node = SsNode::query()->whereId($id)->first();
 		// 使用DDNS的node先获取ipv4地址
 		if($node->is_ddns){
@@ -119,7 +121,7 @@ class NodeController extends Controller {
 				$node->is_ddns = intval($request->input('is_ddns'));
 				$node->is_relay = intval($request->input('is_relay'));
 				$node->is_udp = intval($request->input('is_udp'));
-				$node->ssh_port = $request->input('ssh_port');
+				$node->push_port = $request->input('push_port');
 				$node->detection_type = $request->input('detection_type');
 				$node->compatible = intval($request->input('compatible'));
 				$node->single = intval($request->input('single'));
@@ -135,8 +137,7 @@ class NodeController extends Controller {
 				$node->v2_host = $request->input('v2_host');
 				$node->v2_path = $request->input('v2_path');
 				$node->v2_tls = intval($request->input('v2_tls'));
-				$node->v2_tls_insecure = intval($request->input('v2_tls_insecure'));
-				$node->v2_tls_insecure_ciphers = intval($request->input('v2_tls_insecure_ciphers'));
+				$node->tls_provider = $request->input('tls_provider');
 				$node->save();
 
 				DB::commit();
@@ -175,40 +176,38 @@ class NodeController extends Controller {
 		}
 
 		$validator = Validator::make($request->all(), [
-			'type'                    => 'required|between:1,3',
-			'name'                    => 'required',
-			'country_code'            => 'required',
-			'server'                  => 'required_if:is_ddns,1',
-			'ssh_port'                => 'numeric|between:0,65535',
-			'traffic_rate'            => 'required|numeric|min:0',
-			'level'                   => 'required|numeric|between:0,255',
-			'speed_limit'             => 'required|numeric|min:0',
-			'client_limit'            => 'required|numeric|min:0',
-			'port'                    => 'numeric|between:0,65535',
-			'ip'                      => 'ipv4',
-			'ipv6'                    => 'nullable|ipv6',
-			'relay_server'            => 'required_if:is_relay,1',
-			'relay_port'              => 'required_if:is_relay,1|numeric|between:0,65535',
-			'method'                  => 'required_if:type,1',
-			'protocol'                => 'required_if:type,1',
-			'obfs'                    => 'required_if:type,1',
-			'is_subscribe'            => 'boolean',
-			'is_ddns'                 => 'boolean',
-			'is_relay'                => 'boolean',
-			'is_udp'                  => 'boolean',
-			'detection_type'          => 'between:0,3',
-			'compatible'              => 'boolean',
-			'single'                  => 'boolean',
-			'sort'                    => 'required|numeric|between:0,255',
-			'status'                  => 'boolean',
-			'v2_alter_id'             => 'required_if:type,2|numeric|between:0,65535',
-			'v2_port'                 => 'required_if:type,2|numeric|between:0,65535',
-			'v2_method'               => 'required_if:type,2',
-			'v2_net'                  => 'required_if:type,2',
-			'v2_type'                 => 'required_if:type,2',
-			'v2_tls'                  => 'boolean',
-			'v2_tls_insecure'         => 'required_if:v2_tls,1|boolean',
-			'v2_tls_insecure_ciphers' => 'required_if:v2_tls,1|boolean'
+			'type'           => 'required|between:1,3',
+			'name'           => 'required',
+			'country_code'   => 'required',
+			'server'         => 'required_if:is_ddns,1',
+			'push_port'      => 'numeric|between:0,65535',
+			'traffic_rate'   => 'required|numeric|min:0',
+			'level'          => 'required|numeric|between:0,255',
+			'speed_limit'    => 'required|numeric|min:0',
+			'client_limit'   => 'required|numeric|min:0',
+			'port'           => 'numeric|between:0,65535',
+			'ip'             => 'ipv4',
+			'ipv6'           => 'nullable|ipv6',
+			'relay_server'   => 'required_if:is_relay,1',
+			'relay_port'     => 'required_if:is_relay,1|numeric|between:0,65535',
+			'method'         => 'required_if:type,1',
+			'protocol'       => 'required_if:type,1',
+			'obfs'           => 'required_if:type,1',
+			'is_subscribe'   => 'boolean',
+			'is_ddns'        => 'boolean',
+			'is_relay'       => 'boolean',
+			'is_udp'         => 'boolean',
+			'detection_type' => 'between:0,3',
+			'compatible'     => 'boolean',
+			'single'         => 'boolean',
+			'sort'           => 'required|numeric|between:0,255',
+			'status'         => 'boolean',
+			'v2_alter_id'    => 'required_if:type,2|numeric|between:0,65535',
+			'v2_port'        => 'required_if:type,2|numeric|between:0,65535',
+			'v2_method'      => 'required_if:type,2',
+			'v2_net'         => 'required_if:type,2',
+			'v2_type'        => 'required_if:type,2',
+			'v2_tls'         => 'boolean'
 		], [
 			'server.required_unless' => '开启DDNS, 域名不能为空',
 		]);
@@ -248,46 +247,45 @@ class NodeController extends Controller {
 				DB::beginTransaction();
 
 				$data = [
-					'type'                    => $request->input('type'),
-					'name'                    => $request->input('name'),
-					'country_code'            => $request->input('country_code'),
-					'server'                  => $request->input('server'),
-					'ip'                      => $request->input('ip'),
-					'ipv6'                    => $request->input('ipv6'),
-					'relay_server'            => $request->input('relay_server'),
-					'relay_port'              => $request->input('relay_port'),
-					'level'                   => $request->input('level'),
-					'speed_limit'             => $request->input('speed_limit'),
-					'client_limit'            => $request->input('client_limit'),
-					'description'             => $request->input('description'),
-					'method'                  => $request->input('method'),
-					'protocol'                => $request->input('protocol'),
-					'protocol_param'          => $request->input('protocol_param'),
-					'obfs'                    => $request->input('obfs'),
-					'obfs_param'              => $request->input('obfs_param'),
-					'traffic_rate'            => $request->input('traffic_rate'),
-					'is_subscribe'            => intval($request->input('is_subscribe')),
-					'is_ddns'                 => intval($request->input('is_ddns')),
-					'is_relay'                => intval($request->input('is_relay')),
-					'is_udp'                  => intval($request->input('is_udp')),
-					'ssh_port'                => $request->input('ssh_port'),
-					'detection_type'          => $request->input('detection_type'),
-					'compatible'              => intval($request->input('compatible')),
-					'single'                  => intval($request->input('single')),
-					'port'                    => $request->input('port'),
-					'passwd'                  => $request->input('passwd'),
-					'sort'                    => $request->input('sort'),
-					'status'                  => intval($request->input('status')),
-					'v2_alter_id'             => $request->input('v2_alter_id'),
-					'v2_port'                 => $request->input('v2_port'),
-					'v2_method'               => $request->input('v2_method'),
-					'v2_net'                  => $request->input('v2_net'),
-					'v2_type'                 => $request->input('v2_type'),
-					'v2_host'                 => $request->input('v2_host'),
-					'v2_path'                 => $request->input('v2_path'),
-					'v2_tls'                  => intval($request->input('v2_tls')),
-					'v2_tls_insecure'         => intval($request->input('v2_tls_insecure')),
-					'v2_tls_insecure_ciphers' => intval($request->input('v2_tls_insecure_ciphers'))
+					'type'           => $request->input('type'),
+					'name'           => $request->input('name'),
+					'country_code'   => $request->input('country_code'),
+					'server'         => $request->input('server'),
+					'ip'             => $request->input('ip'),
+					'ipv6'           => $request->input('ipv6'),
+					'relay_server'   => $request->input('relay_server'),
+					'relay_port'     => $request->input('relay_port'),
+					'level'          => $request->input('level'),
+					'speed_limit'    => $request->input('speed_limit'),
+					'client_limit'   => $request->input('client_limit'),
+					'description'    => $request->input('description'),
+					'method'         => $request->input('method'),
+					'protocol'       => $request->input('protocol'),
+					'protocol_param' => $request->input('protocol_param'),
+					'obfs'           => $request->input('obfs'),
+					'obfs_param'     => $request->input('obfs_param'),
+					'traffic_rate'   => $request->input('traffic_rate'),
+					'is_subscribe'   => intval($request->input('is_subscribe')),
+					'is_ddns'        => intval($request->input('is_ddns')),
+					'is_relay'       => intval($request->input('is_relay')),
+					'is_udp'         => intval($request->input('is_udp')),
+					'push_port'      => $request->input('push_port'),
+					'detection_type' => $request->input('detection_type'),
+					'compatible'     => intval($request->input('compatible')),
+					'single'         => intval($request->input('single')),
+					'port'           => $request->input('port'),
+					'passwd'         => $request->input('passwd'),
+					'sort'           => $request->input('sort'),
+					'status'         => intval($request->input('status')),
+					'v2_alter_id'    => $request->input('v2_alter_id'),
+					'v2_port'        => $request->input('v2_port'),
+					'v2_method'      => $request->input('v2_method'),
+					'v2_net'         => $request->input('v2_net'),
+					'v2_type'        => $request->input('v2_type'),
+					'v2_host'        => $request->input('v2_host'),
+					'v2_path'        => $request->input('v2_path'),
+					'v2_tls'         => intval($request->input('v2_tls')),
+					'tls_provider'   => $request->input('tls_provider')
 				];
 
 				// 生成节点标签
@@ -451,7 +449,6 @@ class NodeController extends Controller {
 
 	// Ping节点延迟日志
 	public function pingLog(Request $request) {
-
 		$node_id = $request->input('nodeId');
 		$query = SsNodePing::query();
 		if(isset($node_id)){
@@ -463,4 +460,52 @@ class NodeController extends Controller {
 
 		return Response::view('admin.logs.nodePingLog', $view);
 	}
+
+	// 节点授权列表
+	public function authList(Request $request) {
+		$view['list'] = NodeAuth::query()->orderBy('id')->paginate(15)->appends($request->except('page'));
+		return Response::view('admin.node.authList', $view);
+	}
+
+	// 添加节点授权
+	public function addAuth() {
+		$nodeArray = SsNode::query()->whereStatus(1)->orderBy('id')->pluck('id')->toArray();
+		$authArray = NodeAuth::query()->orderBy('id')->pluck('node_id')->toArray();
+
+		if($nodeArray == $authArray){
+			return Response::json(['status' => 'success', 'message' => '没有需要生成授权的节点']);
+		}else{
+			foreach(array_diff($nodeArray, $authArray) as $nodeId){
+				$obj = new NodeAuth();
+				$obj->node_id = $nodeId;
+				$obj->key = makeRandStr(16);
+				$obj->secret = makeRandStr(8);
+				$obj->save();
+			}
+		}
+		return Response::json(['status' => 'success', 'message' => '生成成功']);
+	}
+
+	// 删除节点授权
+	public function delAuth(Request $request) {
+		try{
+			NodeAuth::query()->whereId($request->input('id'))->delete();
+		}catch(Exception $e){
+			return Response::json(['status' => 'fail', 'message' => '错误:'.var_export($e, true)]);
+		}
+		return Response::json(['status' => 'success', 'message' => '操作成功']);
+	}
+
+	// 重置节点授权
+	public function refreshAuth(Request $request) {
+		$ret = NodeAuth::query()->whereId($request->input('id'))->update([
+			'key'    => makeRandStr(16),
+			'secret' => makeRandStr(8)
+		]);
+		if($ret){
+			return Response::json(['status' => 'success', 'message' => '操作成功']);
+		}else{
+			return Response::json(['status' => 'fail', 'message' => '操作失败']);
+		}
+	}
 }

+ 2 - 1
app/Http/Controllers/PaymentController.php

@@ -188,7 +188,8 @@ class PaymentController extends Controller {
 		return self::getClient()->purchase($request);
 	}
 
-	public function close($oid) {
+	public function close(Request $request) {
+		$oid = $request->input('oid');
 		$order = Order::query()->whereOid($oid)->first();
 		$payment = Payment::query()->whereOid($oid)->first();
 		if($order){

+ 1 - 1
app/Http/Controllers/User/SubscribeController.php

@@ -91,7 +91,7 @@ class SubscribeController extends Controller {
 				break;
 			}
 
-			$scheme .= $this->getNodeInfo($user->id, $node['id'], 0).PHP_EOL;
+			$scheme .= $this->getUserNodeInfo($user->id, $node['id'], 0).PHP_EOL;
 		}
 
 		$headers = [

+ 1 - 1
app/Http/Controllers/UserController.php

@@ -175,7 +175,7 @@ class UserController extends Controller {
 			$node = SsNode::query()->whereId($node_id)->first();
 			// 生成节点信息
 			$proxyType = $node->type == 1? ($node->compatible? 'SS' : 'SSR') : 'V2Ray';
-			$data = $this->getNodeInfo(Auth::id(), $node->id, $infoType != 'text'? 0 : 1);
+			$data = $this->getUserNodeInfo(Auth::id(), $node->id, $infoType != 'text'? 0 : 1);
 
 			return Response::json(['status' => 'success', 'data' => $data, 'title' => $proxyType]);
 		}else{

+ 22 - 0
app/Http/Kernel.php

@@ -16,9 +16,11 @@ use App\Http\Middleware\SetLocale;
 use App\Http\Middleware\TrimStrings;
 use App\Http\Middleware\TrustProxies;
 use App\Http\Middleware\VerifyCsrfToken;
+use App\Http\Middleware\WebApi;
 use Illuminate\Auth\Middleware\Authenticate;
 use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
 use Illuminate\Auth\Middleware\Authorize;
+use Illuminate\Auth\Middleware\EnsureEmailIsVerified;
 use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
 use Illuminate\Foundation\Http\Kernel as HttpKernel;
 use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
@@ -27,6 +29,7 @@ use Illuminate\Http\Middleware\SetCacheHeaders;
 use Illuminate\Routing\Middleware\SubstituteBindings;
 use Illuminate\Routing\Middleware\ThrottleRequests;
 use Illuminate\Routing\Middleware\ValidateSignature;
+use Illuminate\Session\Middleware\AuthenticateSession;
 use Illuminate\Session\Middleware\StartSession;
 use Illuminate\View\Middleware\ShareErrorsFromSession;
 
@@ -85,6 +88,8 @@ class Kernel extends HttpKernel {
 		'guest'         => RedirectIfAuthenticated::class,
 		'signed'        => ValidateSignature::class,
 		'throttle'      => ThrottleRequests::class,
+		'verified'      => EnsureEmailIsVerified::class,
+		'webApi'        => WebApi::class,
 		'isAdmin'       => isAdmin::class,
 		'isAdminLogin'  => isAdminLogin::class,
 		'isLogin'       => isLogin::class,
@@ -94,4 +99,21 @@ class Kernel extends HttpKernel {
 		'affiliate'     => Affiliate::class,
 
 	];
+
+
+	/**
+	 * The priority-sorted list of middleware.
+	 *
+	 * This forces non-global middleware to always be in the given order.
+	 *
+	 * @var array
+	 */
+	protected $middlewarePriority = [
+		StartSession::class,
+		ShareErrorsFromSession::class,
+		Middleware\Authenticate::class,
+		AuthenticateSession::class,
+		SubstituteBindings::class,
+		Authorize::class,
+	];
 }

+ 19 - 0
app/Http/Middleware/Authenticate.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace App\Http\Middleware;
+
+use Illuminate\Auth\Middleware\Authenticate as Middleware;
+
+class Authenticate extends Middleware {
+	/**
+	 * Get the path the user should be redirected to when they are not authenticated.
+	 *
+	 * @param  \Illuminate\Http\Request  $request
+	 * @return string
+	 */
+	protected function redirectTo($request) {
+		if(!$request->expectsJson()){
+			return route('login');
+		}
+	}
+}

+ 2 - 1
app/Http/Middleware/RedirectIfAuthenticated.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Middleware;
 
+use Auth;
 use Closure;
 use Illuminate\Http\Request;
 
@@ -16,7 +17,7 @@ class RedirectIfAuthenticated {
 	 * @return mixed
 	 */
 	public function handle($request, Closure $next, $guard = null) {
-		if(auth()->guard($guard)->check()){
+		if(Auth::guard($guard)->check()){
 			return redirect('/');
 		}
 

+ 2 - 2
app/Http/Middleware/TrustProxies.php

@@ -9,14 +9,14 @@ class TrustProxies extends Middleware {
 	/**
 	 * The trusted proxies for this application.
 	 *
-	 * @var array
+	 * @var array|string
 	 */
 	protected $proxies;
 
 	/**
 	 * The headers that should be used to detect proxies.
 	 *
-	 * @var string
+	 * @var int
 	 */
 	protected $headers = Request::HEADER_X_FORWARDED_ALL;
 }

+ 7 - 0
app/Http/Middleware/VerifyCsrfToken.php

@@ -5,6 +5,13 @@ namespace App\Http\Middleware;
 use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
 
 class VerifyCsrfToken extends Middleware {
+	/**
+	 * Indicates whether the XSRF-TOKEN cookie should be set on the response.
+	 *
+	 * @var bool
+	 */
+	protected $addHttpCookie = true;
+
 	/**
 	 * The URIs that should be excluded from CSRF verification.
 	 *

+ 41 - 16
app/Http/Middleware/WebApi.php

@@ -2,42 +2,67 @@
 
 namespace App\Http\Middleware;
 
+use App\Models\NodeAuth;
+use App\Models\SsNode;
 use Closure;
-use Illuminate\Http\Request;
 use Response;
 
-class WebApi{
+class WebApi {
 	/**
 	 * Handle an incoming request.
 	 *
-	 * @param  Request  $request
+	 * @param           $request
 	 * @param  Closure  $next
 	 *
 	 * @return mixed
 	 */
 	public function handle($request, Closure $next) {
-		$key = $request->input('key');
-		// 未提供 key
-		if($key === null){
+		$id = $request->id;
+		$key = $request->header('key');
+		$time = $request->header('timestamp');
+
+		if($key === null){	// 未提供 key
+			return Response::json([
+				"status"  => "fail",
+				"code"    => 404,
+				"data"    => "",
+				"message" => "Your key is null"
+			]);
+		}elseif($id === null){// 未提供 node
+			return Response::json([
+				"status"  => "fail",
+				"code"    => 404,
+				"data"    => "",
+				"message" => "Your Node Id is null"
+			]);
+		}
+
+		$node = SsNode::query()->whereId($id)->first();
+		if(!$node){// node不存在
 			return Response::json([
-				'ret'  => 0,
-				'data' => 'Your key is null'
+				"status"  => "fail",
+				"code"    => 404,
+				"data"    => "",
+				"message" => "Unknown Node"
 			]);
 		}
 
-		if(!in_array($key, env('WEB_API_KEY'))){
-			// key 不存在
+		$nodeAuth = NodeAuth::query()->whereNodeId($id)->first();
+		if(!$nodeAuth || $key != $nodeAuth->key){// key不存在/不匹配
 			return Response::json([
-				'ret'  => 0,
-				'data' => 'Token is invalid'
+				"status"  => "fail",
+				"code"    => 404,
+				"data"    => "",
+				"message" => "Token is invalid"
 			]);
 		}
 
-		if(env('WEB_API') == false){
-			// 主站不提供 Webapi
+		if(abs($time - time()) >= 300){//时差超过5分钟
 			return Response::json([
-				'ret'  => 0,
-				'data' => 'We regret this service is temporarily unavailable'
+				"status"  => "fail",
+				"code"    => 404,
+				"data"    => "",
+				"message" => "Please resynchronize the server time!"
 			]);
 		}
 

+ 1 - 1
app/Models/Article.php

@@ -10,12 +10,12 @@ use Illuminate\Database\Query\Builder;
  * 文章
  *
  * @property int                             $id
- * @property int|null                        $type       类型:1-文章、2-站内公告、3-站外公告
  * @property string                          $title      标题
  * @property string|null                     $author     作者
  * @property string|null                     $summary    简介
  * @property string|null                     $logo       LOGO
  * @property string|null                     $content    内容
+ * @property int|null                        $type       类型:1-文章、2-站内公告、3-站外公告
  * @property int                             $sort       排序
  * @property \Illuminate\Support\Carbon|null $created_at 创建时间
  * @property \Illuminate\Support\Carbon|null $updated_at 最后更新时间

+ 1 - 1
app/Models/Goods.php

@@ -17,7 +17,7 @@ use Illuminate\Database\Query\Builder;
  * @property int                             $price       售价,单位分
  * @property int                             $level       购买后给用户授权的等级
  * @property int                             $renew       流量重置价格,单位分
- * @property int|null                        $period      流量自动重置周期
+ * @property int                             $period      流量自动重置周期
  * @property string|null                     $info        商品信息
  * @property string|null                     $description 商品描述
  * @property int                             $days        有效期

+ 13 - 15
app/Models/Invite.php

@@ -3,27 +3,25 @@
 namespace App\Models;
 
 use Auth;
-use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;
 use Illuminate\Database\Query\Builder;
-use Illuminate\Support\Carbon;
 
 /**
  * 邀请码
  *
- * @property int            $id
- * @property int            $uid        邀请人ID
- * @property int            $fuid       受邀人ID
- * @property string         $code       邀请码
- * @property int            $status     邀请码状态:0-未使用、1-已使用、2-已过期
- * @property string|null    $dateline   有效期至
- * @property Carbon|null    $created_at
- * @property Carbon|null    $updated_at
- * @property Carbon|null    $deleted_at 删除时间
- * @property-read User|null $generator
- * @property-read mixed     $status_label
- * @property-read User|null $user
+ * @property int                             $id
+ * @property int                             $uid        邀请人ID
+ * @property int                             $fuid       受邀人ID
+ * @property string                          $code       邀请码
+ * @property int                             $status     邀请码状态:0-未使用、1-已使用、2-已过期
+ * @property string|null                     $dateline   有效期至
+ * @property \Illuminate\Support\Carbon|null $created_at
+ * @property \Illuminate\Support\Carbon|null $updated_at
+ * @property \Illuminate\Support\Carbon|null $deleted_at 删除时间
+ * @property-read \App\Models\User|null      $generator
+ * @property-read mixed                      $status_label
+ * @property-read \App\Models\User|null      $user
  * @method static \Illuminate\Database\Eloquent\Builder|Invite newModelQuery()
  * @method static \Illuminate\Database\Eloquent\Builder|Invite newQuery()
  * @method static Builder|Invite onlyTrashed()
@@ -40,7 +38,7 @@ use Illuminate\Support\Carbon;
  * @method static \Illuminate\Database\Eloquent\Builder|Invite whereUpdatedAt($value)
  * @method static Builder|Invite withTrashed()
  * @method static Builder|Invite withoutTrashed()
- * @mixin Eloquent
+ * @mixin \Eloquent
  */
 class Invite extends Model {
 	use SoftDeletes;

+ 36 - 0
app/Models/NodeAuth.php

@@ -0,0 +1,36 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * App\Models\NodeAuth
+ *
+ * @property int                             $id
+ * @property int                             $node_id    授权节点ID
+ * @property string|null                     $key        认证KEY
+ * @property string|null                     $secret     通信密钥
+ * @property \Illuminate\Support\Carbon|null $created_at 创建时间
+ * @property \Illuminate\Support\Carbon|null $updated_at 最后更新时间
+ * @property-read \App\Models\SsNode|null    $node
+ * @method static Builder|NodeAuth newModelQuery()
+ * @method static Builder|NodeAuth newQuery()
+ * @method static Builder|NodeAuth query()
+ * @method static Builder|NodeAuth whereCreatedAt($value)
+ * @method static Builder|NodeAuth whereId($value)
+ * @method static Builder|NodeAuth whereKey($value)
+ * @method static Builder|NodeAuth whereNodeId($value)
+ * @method static Builder|NodeAuth whereSecret($value)
+ * @method static Builder|NodeAuth whereUpdatedAt($value)
+ * @mixin \Eloquent
+ */
+class NodeAuth extends Model {
+	protected $table = 'node_auth';
+	protected $primaryKey = 'id';
+
+	function node() {
+		return $this->hasOne(SsNode::class, 'id', 'node_id');
+	}
+}

+ 31 - 0
app/Models/NodeCertificate.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace App\Models;
+
+use Illuminate\Database\Eloquent\Builder;
+use Illuminate\Database\Eloquent\Model;
+
+/**
+ * App\Models\NodeCertificate
+ *
+ * @property int                        $id
+ * @property string                     $domain 域名
+ * @property string|null                $key    域名证书KEY
+ * @property string|null                $pem    域名证书PEM
+ * @property \Illuminate\Support\Carbon $created_at
+ * @property \Illuminate\Support\Carbon $updated_at
+ * @method static Builder|NodeCertificate newModelQuery()
+ * @method static Builder|NodeCertificate newQuery()
+ * @method static Builder|NodeCertificate query()
+ * @method static Builder|NodeCertificate whereCreatedAt($value)
+ * @method static Builder|NodeCertificate whereDomain($value)
+ * @method static Builder|NodeCertificate whereId($value)
+ * @method static Builder|NodeCertificate whereKey($value)
+ * @method static Builder|NodeCertificate wherePem($value)
+ * @method static Builder|NodeCertificate whereUpdatedAt($value)
+ * @mixin \Eloquent
+ */
+class NodeCertificate extends Model {
+	protected $table = 'node_certificate';
+	protected $primaryKey = 'id';
+}

+ 2 - 2
app/Models/NotificationLog.php

@@ -11,8 +11,8 @@ use Illuminate\Database\Eloquent\Model;
  * @property int                             $id
  * @property int                             $type       类型:1-邮件、2-ServerChan、3-Bark、4-Telegram
  * @property string                          $address    收信地址
- * @property string                          $title      标题
- * @property string                          $content    内容
+ * @property string|null                     $title      邮件标题
+ * @property string|null                     $content    邮件内容
  * @property int                             $status     状态:-1发送失败、0-等待发送、1-发送成功
  * @property string|null                     $error      发送失败抛出的异常信息
  * @property \Illuminate\Support\Carbon|null $created_at 创建时间

+ 22 - 0
app/Models/Rule.php

@@ -14,6 +14,7 @@ use Illuminate\Database\Eloquent\Model;
  * @property string                     $pattern 规则值
  * @property \Illuminate\Support\Carbon $created_at
  * @property \Illuminate\Support\Carbon $updated_at
+ * @property-read mixed                 $type_api_label
  * @property-read mixed                 $type_label
  * @method static Builder|Rule newModelQuery()
  * @method static Builder|Rule newQuery()
@@ -50,4 +51,25 @@ class Rule extends Model {
 		}
 		return $type_label;
 	}
+
+	function getTypeApiLabelAttribute() {
+		switch($this->attributes['type']){
+			case 1:
+				$type_api_label = 'reg';
+				break;
+			case 2:
+				$type_api_label = 'domain';
+				break;
+			case 3:
+				$type_api_label = 'ip';
+				break;
+			case 4:
+				$type_api_label = 'protocol';
+				break;
+			default:
+				$type_api_label = 'unknown';
+
+		}
+		return $type_api_label;
+	}
 }

+ 1 - 1
app/Models/RuleGroup.php

@@ -9,7 +9,7 @@ use Illuminate\Database\Eloquent\Model;
  * 审计规则分组
  *
  * @property int                             $id
- * @property int|null                        $type  模式:1-阻断、2-仅放行
+ * @property int|null                        $type  模式:1-阻断、0-放行
  * @property string|null                     $name  分组名称
  * @property string|null                     $rules 关联的规则ID,多个用,号分隔
  * @property string|null                     $nodes 关联的节点ID,多个用,号分隔

+ 64 - 43
app/Models/SsNode.php

@@ -9,48 +9,49 @@ use Illuminate\Database\Eloquent\Model;
  * SS节点信息
  *
  * @property int                                                                     $id
- * @property int                                                                     $type                    服务类型:1-ShadowsocksR、2-V2ray
- * @property string                                                                  $name                    名称
- * @property string                                                                  $country_code            国家代码
- * @property string|null                                                             $server                  服务器域名地址
- * @property string|null                                                             $ip                      服务器IPV4地址
- * @property string|null                                                             $ipv6                    服务器IPV6地址
- * @property string|null                                                             $relay_server            中转地址
- * @property int|null                                                                $relay_port              中转端口
- * @property \App\Models\Level|null                                                  $level                   等级:0-无等级,全部可见
- * @property int                                                                     $speed_limit             节点限速,为0表示不限速,单位Byte
- * @property int                                                                     $client_limit            设备数限制
- * @property string|null                                                             $description             节点简单描述
- * @property string                                                                  $method                  加密方式
- * @property string                                                                  $protocol                协议
- * @property string|null                                                             $protocol_param          协议参数
- * @property string                                                                  $obfs                    混淆
- * @property string|null                                                             $obfs_param              混淆参数
- * @property float                                                                   $traffic_rate            流量比率
- * @property int                                                                     $is_subscribe            是否允许用户订阅该节点:0-否、1-是
- * @property int                                                                     $is_ddns                 是否使用DDNS:0-否、1-是
- * @property int                                                                     $is_relay                是否中转节点:0-否、1-是
- * @property int                                                                     $is_udp                  是否启用UDP:0-不启用、1-启用
- * @property int                                                                     $ssh_port                SSH端口
- * @property int                                                                     $detection_type          节点检测: 0-关闭、1-只检测TCP、2-只检测ICMP、3-检测全部
- * @property int                                                                     $compatible              兼容SS
- * @property int                                                                     $single                  启用单端口功能:0-否、1-是
- * @property int|null                                                                $port                    单端口的端口号或连接端口号
- * @property string|null                                                             $passwd                  单端口的连接密码
- * @property int                                                                     $sort                    排序值,值越大越靠前显示
- * @property int                                                                     $status                  状态:0-维护、1-正常
- * @property int                                                                     $v2_alter_id             V2Ray额外ID
- * @property int                                                                     $v2_port                 V2Ray服务端口
- * @property string                                                                  $v2_method               V2Ray加密方式
- * @property string                                                                  $v2_net                  V2Ray传输协议
- * @property string                                                                  $v2_type                 V2Ray伪装类型
- * @property string                                                                  $v2_host                 V2Ray伪装的域名
- * @property string                                                                  $v2_path                 V2Ray的WS/H2路径
- * @property int                                                                     $v2_tls                  V2Ray后端TLS:0-未开启、1-开启
- * @property int                                                                     $v2_tls_insecure         是否允许不安全连接
- * @property int                                                                     $v2_tls_insecure_ciphers 是否允许不安全的加密方式
+ * @property int                                                                     $type           服务类型:1-ShadowsocksR、2-V2ray
+ * @property string                                                                  $name           名称
+ * @property string|null                                                             $country_code   国家代码
+ * @property string|null                                                             $server         服务器域名地址
+ * @property string|null                                                             $ip             服务器IPV4地址
+ * @property string|null                                                             $ipv6           服务器IPV6地址
+ * @property string|null                                                             $relay_server   中转地址
+ * @property int|null                                                                $relay_port     中转端口
+ * @property int                                                                     $level          等级:0-无等级,全部可见
+ * @property int                                                                     $speed_limit    节点限速,为0表示不限速,单位Byte
+ * @property int                                                                     $client_limit   设备数限制
+ * @property string|null                                                             $description    节点简单描述
+ * @property string                                                                  $method         加密方式
+ * @property string                                                                  $protocol       协议
+ * @property string|null                                                             $protocol_param 协议参数
+ * @property string                                                                  $obfs           混淆
+ * @property string|null                                                             $obfs_param     混淆参数
+ * @property float                                                                   $traffic_rate   流量比率
+ * @property int                                                                     $is_subscribe   是否允许用户订阅该节点:0-否、1-是
+ * @property int                                                                     $is_ddns        是否使用DDNS:0-否、1-是
+ * @property int                                                                     $is_relay       是否中转节点:0-否、1-是
+ * @property int                                                                     $is_udp         是否启用UDP:0-不启用、1-启用
+ * @property int                                                                     $push_port      消息推送端口
+ * @property int                                                                     $detection_type 节点检测: 0-关闭、1-只检测TCP、2-只检测ICMP、3-检测全部
+ * @property int                                                                     $compatible     兼容SS
+ * @property int                                                                     $single         启用单端口功能:0-否、1-是
+ * @property int|null                                                                $port           单端口的端口号或连接端口号
+ * @property string|null                                                             $passwd         单端口的连接密码
+ * @property int                                                                     $sort           排序值,值越大越靠前显示
+ * @property int                                                                     $status         状态:0-维护、1-正常
+ * @property int                                                                     $v2_alter_id    V2Ray额外ID
+ * @property int                                                                     $v2_port        V2Ray服务端口
+ * @property string                                                                  $v2_method      V2Ray加密方式
+ * @property string                                                                  $v2_net         V2Ray传输协议
+ * @property string                                                                  $v2_type        V2Ray伪装类型
+ * @property string                                                                  $v2_host        V2Ray伪装的域名
+ * @property string                                                                  $v2_path        V2Ray的WS/H2路径
+ * @property int                                                                     $v2_tls         V2Ray连接TLS:0-未开启、1-开启
+ * @property string|null                                                             $tls_provider   V2Ray节点的TLS提供商授权信息
  * @property \Illuminate\Support\Carbon                                              $created_at
  * @property \Illuminate\Support\Carbon                                              $updated_at
+ * @property-read \App\Models\NodeAuth|null                                          $auth
+ * @property-read mixed                                                              $type_label
  * @property-read \Illuminate\Database\Eloquent\Collection|\App\Models\SsNodeLabel[] $label
  * @property-read int|null                                                           $label_count
  * @method static Builder|SsNode newModelQuery()
@@ -78,14 +79,15 @@ use Illuminate\Database\Eloquent\Model;
  * @method static Builder|SsNode wherePort($value)
  * @method static Builder|SsNode whereProtocol($value)
  * @method static Builder|SsNode whereProtocolParam($value)
+ * @method static Builder|SsNode wherePushPort($value)
  * @method static Builder|SsNode whereRelayPort($value)
  * @method static Builder|SsNode whereRelayServer($value)
  * @method static Builder|SsNode whereServer($value)
  * @method static Builder|SsNode whereSingle($value)
  * @method static Builder|SsNode whereSort($value)
  * @method static Builder|SsNode whereSpeedLimit($value)
- * @method static Builder|SsNode whereSshPort($value)
  * @method static Builder|SsNode whereStatus($value)
+ * @method static Builder|SsNode whereTlsProvider($value)
  * @method static Builder|SsNode whereTrafficRate($value)
  * @method static Builder|SsNode whereType($value)
  * @method static Builder|SsNode whereUpdatedAt($value)
@@ -96,8 +98,6 @@ use Illuminate\Database\Eloquent\Model;
  * @method static Builder|SsNode whereV2Path($value)
  * @method static Builder|SsNode whereV2Port($value)
  * @method static Builder|SsNode whereV2Tls($value)
- * @method static Builder|SsNode whereV2TlsInsecure($value)
- * @method static Builder|SsNode whereV2TlsInsecureCiphers($value)
  * @method static Builder|SsNode whereV2Type($value)
  * @mixin \Eloquent
  */
@@ -109,7 +109,28 @@ class SsNode extends Model {
 		return $this->hasMany(SsNodeLabel::class, 'node_id', 'id');
 	}
 
+	function auth() {
+		return $this->hasOne(NodeAuth::class, 'node_id', 'id');
+	}
+
 	function getLevel() {
 		return $this->hasOne(Level::class, 'level', 'level');
 	}
+
+	function getTypeLabelAttribute() {
+		switch($this->attributes['type']){
+			case 1:
+				$type_label = 'ShadowsocksR';
+				break;
+			case 2:
+				$type_label = 'V2Ray';
+				break;
+			case 3:
+				$type_label = 'Trojan';
+				break;
+			default:
+				$type_label = 'UnKnown';
+		}
+		return $type_label;
+	}
 }

+ 11 - 10
app/Models/SsNodeIp.php

@@ -8,15 +8,15 @@ use Illuminate\Database\Eloquent\Model;
 /**
  * SS节点在线IP信息
  *
- * @property int                        $id
- * @property int                        $node_id    节点ID
- * @property int                        $user_id    用户ID
- * @property int                        $port       端口
- * @property string                     $type       类型:all、tcp、udp
- * @property string|null                $ip         连接IP:每个IP用,号隔开
- * @property \Illuminate\Support\Carbon $created_at 上报时间
- * @property-read \App\Models\SsNode    $node
- * @property-read \App\Models\User      $user
+ * @property int                     $id
+ * @property int                     $node_id    节点ID
+ * @property int                     $user_id    用户ID
+ * @property int                     $port       端口
+ * @property string                  $type       类型:all、tcp、udp
+ * @property string|null             $ip         连接IP:每个IP用,号隔开
+ * @property int                     $created_at 上报时间
+ * @property-read \App\Models\SsNode $node
+ * @property-read \App\Models\User   $user
  * @method static Builder|SsNodeIp newModelQuery()
  * @method static Builder|SsNodeIp newQuery()
  * @method static Builder|SsNodeIp query()
@@ -30,6 +30,7 @@ use Illuminate\Database\Eloquent\Model;
  * @mixin \Eloquent
  */
 class SsNodeIp extends Model {
+	public $timestamps = false;
 	protected $table = 'ss_node_ip';
 	protected $primaryKey = 'id';
 
@@ -38,6 +39,6 @@ class SsNodeIp extends Model {
 	}
 
 	function user() {
-		return $this->belongsTo(User::class, 'port', 'port');
+		return $this->belongsTo(User::class, 'user_id', 'id');
 	}
 }

+ 1 - 2
app/Models/UserTrafficLog.php

@@ -10,9 +10,9 @@ use Illuminate\Database\Eloquent\Model;
  *
  * @property int                     $id
  * @property int                     $user_id  用户ID
- * @property int                     $node_id  节点ID
  * @property int                     $u        上传流量
  * @property int                     $d        下载流量
+ * @property int                     $node_id  节点ID
  * @property float                   $rate     倍率
  * @property string                  $traffic  产生流量
  * @property int                     $log_time 记录时间
@@ -37,7 +37,6 @@ class UserTrafficLog extends Model {
 	protected $primaryKey = 'id';
 
 	// 关联账号
-
 	function user() {
 		return $this->belongsTo(User::class, 'user_id', 'id');
 	}

+ 12 - 11
app/Providers/AppServiceProvider.php

@@ -7,28 +7,29 @@ use Illuminate\Support\ServiceProvider;
 use URL;
 
 class AppServiceProvider extends ServiceProvider {
+
 	/**
-	 * Bootstrap any application services.
+	 * Register any application services.
 	 *
 	 * @return void
 	 */
-	public function boot() {
-		// 检测是否强制跳转https
-		if(env('REDIRECT_HTTPS', false)){
-			URL::forceScheme('https');
+	public function register() {
+		if($this->app->environment() !== 'production'){
+			$this->app->register(IdeHelperServiceProvider::class);
 		}
-
-		//\Schema::defaultStringLength(191);
 	}
 
 	/**
-	 * Register any application services.
+	 * Bootstrap any application services.
 	 *
 	 * @return void
 	 */
-	public function register() {
-		if($this->app->environment() !== 'production'){
-			$this->app->register(IdeHelperServiceProvider::class);
+	public function boot() {
+		// 检测是否强制跳转https
+		if(env('REDIRECT_HTTPS', false)){
+			URL::forceScheme('https');
 		}
+
+		//\Schema::defaultStringLength(191);
 	}
 }

+ 1 - 2
app/Providers/AuthServiceProvider.php

@@ -10,8 +10,7 @@ class AuthServiceProvider extends ServiceProvider {
 	 *
 	 * @var array
 	 */
-	protected $policies = [
-		'App\Model' => 'App\Policies\ModelPolicy',
+	protected $policies = [// 'App\Model' => 'App\Policies\ModelPolicy',
 	];
 
 	/**

+ 1 - 1
bootstrap/app.php

@@ -12,7 +12,7 @@
 */
 
 $app = new Illuminate\Foundation\Application(
-    realpath(__DIR__ . '/../')
+    $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__)
 );
 
 /*

+ 82 - 78
composer.json

@@ -1,96 +1,100 @@
 {
   "name": "laravel/laravel",
+  "type": "project",
   "description": "The Laravel Framework.",
   "keywords": [
-    "framework",
-    "laravel"
+	"framework",
+	"laravel"
   ],
   "license": "MIT",
-  "type": "project",
   "require": {
-    "php": "^7.2",
-    "ext-curl": "*",
-    "ext-dom": "*",
-    "ext-json": "*",
-    "ext-openssl": "*",
-    "barryvdh/laravel-debugbar": "^3",
-    "barryvdh/laravel-ide-helper": "^2.7",
-    "fideloper/proxy": "^4.3",
-    "guzzlehttp/guzzle": "^6.5",
-    "ipip/db": "^1.0",
-    "itbdw/ip-database": "^2.0",
-    "jenssegers/agent": "^2.6",
-    "laravel/framework": "5.8.*",
-    "laravel/tinker": "~1.0",
-    "mews/captcha": "^3.1",
-    "mews/purifier": "^3.2",
-    "misechow/geetest": "^1.0",
-    "misechow/no-captcha": "^1.0",
-    "openlss/lib-array2xml": "^1.0",
-    "overtrue/laravel-lang": "^3.0",
-    "phpoffice/phpspreadsheet": "^1.13",
-    "predis/predis": "^1.1",
-    "rap2hpoutre/laravel-log-viewer": "^1.6",
-    "riverslei/payment": "*",
-    "scyllaly/hcaptcha": "^4.1",
-    "spatie/laravel-permission": "^3.13",
-    "srmklive/paypal": "~1.0",
-    "xhat/payjs": "^1.4"
+	"php": "^7.2",
+	"ext-curl": "*",
+	"ext-dom": "*",
+	"ext-json": "*",
+	"ext-openssl": "*",
+	"barryvdh/laravel-debugbar": "^3",
+	"barryvdh/laravel-ide-helper": "^2.7",
+	"fideloper/proxy": "^4.3",
+	"guzzlehttp/guzzle": "^6.5",
+	"ipip/db": "^1.0",
+	"itbdw/ip-database": "^2.0",
+	"jenssegers/agent": "^2.6",
+	"laravel/framework": "5.8.*",
+	"laravel/tinker": "^1.0",
+	"mews/captcha": "^3.1",
+	"mews/purifier": "^3.2",
+	"misechow/geetest": "^1.0",
+	"misechow/no-captcha": "^1.0",
+	"openlss/lib-array2xml": "^1.0",
+	"overtrue/laravel-lang": "^3.0",
+	"phpoffice/phpspreadsheet": "^1.13",
+	"predis/predis": "^1.1",
+	"rap2hpoutre/laravel-log-viewer": "^1.6",
+	"riverslei/payment": "*",
+	"scyllaly/hcaptcha": "^4.1",
+	"spatie/laravel-permission": "^3.13",
+	"srmklive/paypal": "~1.0",
+	"xhat/payjs": "^1.4"
   },
   "require-dev": {
-    "filp/whoops": "^2.7",
-    "fzaninotto/faker": "^1.9",
-    "mockery/mockery": "^1.3",
-    "nunomaduro/collision": "^3.0",
-    "phpunit/phpunit": "^8"
+	"beyondcode/laravel-dump-server": "^1.0",
+	"filp/whoops": "^2.7",
+	"fzaninotto/faker": "^1.9",
+	"mockery/mockery": "^1.3",
+	"nunomaduro/collision": "^3.0",
+	"phpunit/phpunit": "^8"
+  },
+  "config": {
+	"optimize-autoloader": true,
+	"preferred-install": "dist",
+	"sort-packages": true
+  },
+  "extra": {
+	"laravel": {
+	  "dont-discover": []
+	}
   },
   "autoload": {
-    "files": [
-      "app/helpers.php"
-    ],
-    "classmap": [
-      "database/seeds",
-      "database/factories"
-    ],
-    "psr-4": {
-      "App\\": "app/"
-    }
+	"psr-4": {
+	  "App\\": "app/"
+	},
+	"classmap": [
+	  "database/seeds",
+	  "database/factories"
+	],
+	"files": [
+	  "app/helpers.php"
+	]
   },
   "autoload-dev": {
-    "psr-4": {
-      "Tests\\": "tests/"
-    }
-  },
-  "extra": {
-    "laravel": {
-      "dont-discover": [
-      ]
-    }
+	"psr-4": {
+	  "Tests\\": "tests/"
+	}
   },
+  "minimum-stability": "dev",
+  "prefer-stable": true,
   "scripts": {
-    "post-root-package-install": [
-      "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
-    ],
-    "post-update-cmd": [
-      "Illuminate\\Foundation\\ComposerScripts::postUpdate",
-      "@php artisan ide-helper:generate",
-      "@php artisan ide-helper:meta"
-    ],
-    "post-create-project-cmd": [
-      "@php artisan key:generate"
-    ]
-  },
-  "config": {
-    "preferred-install": "dist",
-    "sort-packages": true,
-    "optimize-autoloader": true
+	"post-autoload-dump": [
+	  "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
+	  "@php artisan package:discover --ansi"
+	],
+	"post-root-package-install": [
+	  "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
+	],
+	"post-update-cmd": [
+	  "Illuminate\\Foundation\\ComposerScripts::postUpdate",
+	  "@php artisan ide-helper:generate",
+	  "@php artisan ide-helper:meta"
+	],
+	"post-create-project-cmd": [
+	  "@php artisan key:generate --ansi"
+	]
   },
   "repositories": {
-    "packagist": {
-      "type": "composer",
-      "url": "https://mirrors.aliyun.com/composer/"
-    }
-  },
-  "minimum-stability": "dev",
-  "prefer-stable": true
+	"packagist": {
+	  "type": "composer",
+	  "url": "https://mirrors.aliyun.com/composer/"
+	}
+  }
 }

+ 81 - 8
composer.lock

@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "59fe960ac16eef546fe52b6a61a09322",
+    "content-hash": "b9be01372de2521001203096228047f7",
     "packages": [
         {
             "name": "barryvdh/laravel-debugbar",
@@ -3128,16 +3128,16 @@
         },
         {
             "name": "nesbot/carbon",
-            "version": "2.35.0",
+            "version": "2.36.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/briannesbitt/Carbon.git",
-                "reference": "4b9bd835261ef23d36397a46a76b496a458305e5"
+                "reference": "d0b65958d9942fd1b501fdb0800c67e8323aa08d"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/4b9bd835261ef23d36397a46a76b496a458305e5",
-                "reference": "4b9bd835261ef23d36397a46a76b496a458305e5",
+                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/d0b65958d9942fd1b501fdb0800c67e8323aa08d",
+                "reference": "d0b65958d9942fd1b501fdb0800c67e8323aa08d",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -3155,9 +3155,10 @@
             "require-dev": {
                 "doctrine/orm": "^2.7",
                 "friendsofphp/php-cs-fixer": "^2.14 || ^3.0",
-                "kylekatarnls/multi-tester": "^1.1",
+                "kylekatarnls/multi-tester": "^2.0",
                 "phpmd/phpmd": "^2.8",
-                "phpstan/phpstan": "^0.11",
+                "phpstan/extension-installer": "^1.0",
+                "phpstan/phpstan": "^0.12.30",
                 "phpunit/phpunit": "^7.5 || ^8.0",
                 "squizlabs/php_codesniffer": "^3.4"
             },
@@ -3174,6 +3175,11 @@
                     "providers": [
                         "Carbon\\Laravel\\ServiceProvider"
                     ]
+                },
+                "phpstan": {
+                    "includes": [
+                        "extension.neon"
+                    ]
                 }
             },
             "autoload": {
@@ -3203,7 +3209,7 @@
                 "datetime",
                 "time"
             ],
-            "time": "2020-05-24T18:27:52+00:00"
+            "time": "2020-06-25T20:20:01+00:00"
         },
         {
             "name": "nikic/php-parser",
@@ -6449,6 +6455,73 @@
         }
     ],
     "packages-dev": [
+        {
+            "name": "beyondcode/laravel-dump-server",
+            "version": "1.3.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/beyondcode/laravel-dump-server.git",
+                "reference": "fcc88fa66895f8c1ff83f6145a5eff5fa2a0739a"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/beyondcode/laravel-dump-server/zipball/fcc88fa66895f8c1ff83f6145a5eff5fa2a0739a",
+                "reference": "fcc88fa66895f8c1ff83f6145a5eff5fa2a0739a",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "illuminate/console": "5.6.*|5.7.*|5.8.*|^6.0",
+                "illuminate/http": "5.6.*|5.7.*|5.8.*|^6.0",
+                "illuminate/support": "5.6.*|5.7.*|5.8.*|^6.0",
+                "php": "^7.1",
+                "symfony/var-dumper": "^4.1.1"
+            },
+            "require-dev": {
+                "larapack/dd": "^1.0",
+                "phpunit/phpunit": "^7.0"
+            },
+            "type": "library",
+            "extra": {
+                "laravel": {
+                    "providers": [
+                        "BeyondCode\\DumpServer\\DumpServerServiceProvider"
+                    ]
+                }
+            },
+            "autoload": {
+                "psr-4": {
+                    "BeyondCode\\DumpServer\\": "src"
+                },
+                "files": [
+                    "helpers.php"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Marcel Pociot",
+                    "email": "marcel@beyondco.de",
+                    "homepage": "https://beyondco.de",
+                    "role": "Developer"
+                }
+            ],
+            "description": "Symfony Var-Dump Server for Laravel",
+            "homepage": "https://github.com/beyondcode/laravel-dump-server",
+            "keywords": [
+                "beyondcode",
+                "laravel-dump-server"
+            ],
+            "time": "2019-08-11T13:17:40+00:00"
+        },
         {
             "name": "doctrine/instantiator",
             "version": "1.3.1",

+ 20 - 2
config/app.php

@@ -22,7 +22,7 @@ return [
     |
     | This value determines the "environment" your application is currently
     | running in. This may determine how you prefer to configure various
-    | services your application utilizes. Set this in your ".env" file.
+    | services the application utilizes. Set this in your ".env" file.
     |
     */
 
@@ -39,7 +39,7 @@ return [
     |
     */
 
-    'debug' => env('APP_DEBUG', FALSE),
+    'debug' => env('APP_DEBUG', false),
 
     /*
     |--------------------------------------------------------------------------
@@ -54,6 +54,8 @@ return [
 
     'url' => env('APP_URL', 'http://localhost'),
 
+    'asset_url' => env('ASSET_URL', null),
+
     /*
     |--------------------------------------------------------------------------
     | Application Timezone
@@ -93,6 +95,19 @@ return [
 
     'fallback_locale' => env('APP_FALLBACK_LOCALE', 'zh-CN'),
 
+    /*
+    |--------------------------------------------------------------------------
+    | Faker Locale
+    |--------------------------------------------------------------------------
+    |
+    | This locale will be used by the Faker PHP library when generating fake
+    | data for your database seeds. For example, this will be used to get
+    | localized telephone numbers, street address information and more.
+    |
+    */
+
+    'faker_locale' => 'en_US',
+
     /*
     |--------------------------------------------------------------------------
     | Encryption Key
@@ -185,6 +200,7 @@ return [
     'aliases' => [
         'Agent' => Jenssegers\Agent\Facades\Agent::class,
         'App' => Illuminate\Support\Facades\App::class,
+        'Arr' => Illuminate\Support\Arr::class,
         'Artisan' => Illuminate\Support\Facades\Artisan::class,
         'Auth' => Illuminate\Support\Facades\Auth::class,
         'Blade' => Illuminate\Support\Facades\Blade::class,
@@ -221,9 +237,11 @@ return [
         'Schema' => Illuminate\Support\Facades\Schema::class,
         'Session' => Illuminate\Support\Facades\Session::class,
         'Storage' => Illuminate\Support\Facades\Storage::class,
+        'Str' => Illuminate\Support\Str::class,
         'URL' => Illuminate\Support\Facades\URL::class,
         'Validator' => Illuminate\Support\Facades\Validator::class,
         'View' => Illuminate\Support\Facades\View::class,
+
     ],
 
 ];

+ 1 - 0
config/auth.php

@@ -44,6 +44,7 @@ return [
         'api' => [
             'driver' => 'token',
             'provider' => 'users',
+            'hash' => false,
         ],
     ],
 

+ 1 - 1
config/broadcasting.php

@@ -37,7 +37,7 @@ return [
             'app_id' => env('PUSHER_APP_ID'),
             'options' => [
                 'cluster' => env('PUSHER_APP_CLUSTER'),
-                'encrypted' => TRUE,
+                'useTLS' => true,
             ],
         ],
 

+ 17 - 8
config/cache.php

@@ -1,5 +1,7 @@
 <?php
 
+use Illuminate\Support\Str;
+
 return [
 
     /*
@@ -11,7 +13,8 @@ return [
     | using this caching library. This connection is used when another is
     | not explicitly specified when executing a given caching function.
     |
-    | Supported: "apc", "array", "database", "file", "memcached", "redis"
+    | Supported: "apc", "array", "database", "file",
+    |            "memcached", "redis", "dynamodb"
     |
     */
 
@@ -41,7 +44,7 @@ return [
         'database' => [
             'driver' => 'database',
             'table' => 'cache',
-            'connection' => NULL,
+            'connection' => null,
         ],
 
         'file' => [
@@ -57,7 +60,7 @@ return [
                 env('MEMCACHED_PASSWORD'),
             ],
             'options' => [
-                // Memcached::OPT_CONNECT_TIMEOUT  => 2000,
+                // Memcached::OPT_CONNECT_TIMEOUT => 2000,
             ],
             'servers' => [
                 [
@@ -70,7 +73,16 @@ return [
 
         'redis' => [
             'driver' => 'redis',
-            'connection' => 'default',
+            'connection' => 'cache',
+        ],
+
+        'dynamodb' => [
+            'driver' => 'dynamodb',
+            'key' => env('AWS_ACCESS_KEY_ID'),
+            'secret' => env('AWS_SECRET_ACCESS_KEY'),
+            'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
+            'table' => env('DYNAMODB_CACHE_TABLE', 'cache'),
+            'endpoint' => env('DYNAMODB_ENDPOINT'),
         ],
 
     ],
@@ -86,9 +98,6 @@ return [
     |
     */
 
-    'prefix' => env(
-        'CACHE_PREFIX',
-        str_slug(env('APP_NAME', 'laravel'), '_') . '_cache'
-    ),
+    'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache'),
 
 ];

+ 2 - 2
config/captcha.php

@@ -6,11 +6,11 @@ return [
     //'characters' => '2346789abcdefghjmnpqrtuxyzABCDEFGHJMNPQRTUXYZ',
 
     'default' => [
-        'length' => 4, // ���ÿ�ѧ�����Ҫ��Ϊ 9
+        'length' => 4, // 启用科学计算后要改为 9
         'width' => 90,
         'height' => 43,
         'quality' => 90,
-        'math' => FALSE, // ��Ϊtrue�����ÿ�ѧ����
+        'math' => FALSE, // 改为true,启用科学计算
     ],
 
     'flat' => [

+ 33 - 6
config/database.php

@@ -1,5 +1,7 @@
 <?php
 
+use Illuminate\Support\Str;
+
 return [
 
     /*
@@ -35,12 +37,15 @@ return [
 
         'sqlite' => [
             'driver' => 'sqlite',
+            'url' => env('DATABASE_URL'),
             'database' => env('DB_DATABASE', database_path('database.sqlite')),
             'prefix' => '',
+            'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
         ],
 
         'mysql' => [
             'driver' => 'mysql',
+            'url' => env('DATABASE_URL'),
             'host' => env('DB_HOST', '127.0.0.1'),
             'port' => env('DB_PORT', '3306'),
             'database' => env('DB_DATABASE', 'forge'),
@@ -50,12 +55,17 @@ return [
             'charset' => 'utf8mb4',
             'collation' => 'utf8mb4_unicode_ci',
             'prefix' => '',
-            'strict' => env('DB_STRICT', TRUE),
-            'engine' => NULL,
+            'prefix_indexes' => true,
+            'strict' => env('DB_STRICT', true),
+            'engine' => null,
+            'options' => extension_loaded('pdo_mysql') ? array_filter([
+                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
+            ]) : [],
         ],
 
         'pgsql' => [
             'driver' => 'pgsql',
+            'url' => env('DATABASE_URL'),
             'host' => env('DB_HOST', '127.0.0.1'),
             'port' => env('DB_PORT', '5432'),
             'database' => env('DB_DATABASE', 'forge'),
@@ -63,12 +73,14 @@ return [
             'password' => env('DB_PASSWORD', ''),
             'charset' => 'utf8',
             'prefix' => '',
+            'prefix_indexes' => true,
             'schema' => 'public',
             'sslmode' => 'prefer',
         ],
 
         'sqlsrv' => [
             'driver' => 'sqlsrv',
+            'url' => env('DATABASE_URL'),
             'host' => env('DB_HOST', 'localhost'),
             'port' => env('DB_PORT', '1433'),
             'database' => env('DB_DATABASE', 'forge'),
@@ -76,6 +88,7 @@ return [
             'password' => env('DB_PASSWORD', ''),
             'charset' => 'utf8',
             'prefix' => '',
+            'prefix_indexes' => true,
         ],
 
     ],
@@ -99,20 +112,34 @@ return [
     |--------------------------------------------------------------------------
     |
     | Redis is an open source, fast, and advanced key-value store that also
-    | provides a richer set of commands than a typical key-value systems
+    | provides a richer body of commands than a typical key-value system
     | such as APC or Memcached. Laravel makes it easy to dig right in.
     |
     */
 
     'redis' => [
 
-        'client' => 'predis',
+        'client' => env('REDIS_CLIENT', 'predis'),
+
+        'options' => [
+            'cluster' => env('REDIS_CLUSTER', 'predis'),
+            'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'),
+        ],
 
         'default' => [
+            'url' => env('REDIS_URL'),
+            'host' => env('REDIS_HOST', '127.0.0.1'),
+            'password' => env('REDIS_PASSWORD', null),
+            'port' => env('REDIS_PORT', 6379),
+            'database' => env('REDIS_DB', 0),
+        ],
+
+        'cache' => [
+            'url' => env('REDIS_URL'),
             'host' => env('REDIS_HOST', '127.0.0.1'),
-            'password' => env('REDIS_PASSWORD', NULL),
+            'password' => env('REDIS_PASSWORD', null),
             'port' => env('REDIS_PORT', 6379),
-            'database' => 0,
+            'database' => env('REDIS_CACHE_DB', 1),
         ],
 
     ],

+ 1 - 1
config/domains.php

@@ -49,5 +49,5 @@ return [
     'credit', 'courses', 'coupons', 'condos', 'consulting', 'coach', 'cloud', 'clinic', 'click', 'claims', 'city', 'church',
     'chat', 'charity', 'casino', 'cafe', 'buzz', 'business', 'boston', 'blog', 'bio', 'bingo', 'bid', 'beer', 'band', 'audio',
     'auction', 'attorney', 'art', 'army', 'apartments', 'airforce', 'accountants', 'accountant', 'monster', 'dev', 'sydney', 'baby',
-    'melbourne', 'bible', 'yachts', 'motorcycles', 'autos', 'boats', 'homes'
+    'melbourne', 'bible', 'yachts', 'motorcycles', 'autos', 'boats', 'homes', 'best'
 ];

+ 1 - 1
config/filesystems.php

@@ -51,7 +51,7 @@ return [
         'public' => [
             'driver' => 'local',
             'root' => storage_path('app/public'),
-            'url' => env('APP_URL') . '/storage',
+            'url' => env('APP_URL').'/storage',
             'visibility' => 'public',
         ],
 

+ 1 - 1
config/hashing.php

@@ -11,7 +11,7 @@ return [
     | passwords for your application. By default, the bcrypt algorithm is
     | used; however, you remain free to modify this option if you wish.
     |
-    | Supported: "bcrypt", "argon"
+    | Supported: "bcrypt", "argon", "argon2id"
     |
     */
 

+ 15 - 2
config/logging.php

@@ -1,6 +1,7 @@
 <?php
 
 use Monolog\Handler\StreamHandler;
+use Monolog\Handler\SyslogUdpHandler;
 
 return [
 
@@ -35,7 +36,8 @@ return [
     'channels' => [
         'stack' => [
             'driver' => 'stack',
-            'channels' => ['single'],
+            'channels' => ['daily'],
+            'ignore_exceptions' => false,
         ],
 
         'single' => [
@@ -48,7 +50,7 @@ return [
             'driver' => 'daily',
             'path' => storage_path('logs/laravel.log'),
             'level' => 'debug',
-            'days' => 7,
+            'days' => 14,
         ],
 
         'slack' => [
@@ -59,9 +61,20 @@ return [
             'level' => 'critical',
         ],
 
+        'papertrail' => [
+            'driver' => 'monolog',
+            'level' => 'debug',
+            'handler' => SyslogUdpHandler::class,
+            'handler_with' => [
+                'host' => env('PAPERTRAIL_URL'),
+                'port' => env('PAPERTRAIL_PORT'),
+            ],
+        ],
+
         'stderr' => [
             'driver' => 'monolog',
             'handler' => StreamHandler::class,
+            'formatter' => env('LOG_STDERR_FORMATTER'),
             'with' => [
                 'stream' => 'php://stderr',
             ],

+ 9 - 9
config/mail.php

@@ -12,7 +12,7 @@ return [
     | your application here. By default, Laravel is setup for SMTP mail.
     |
     | Supported: "smtp", "sendmail", "mailgun", "mandrill", "ses",
-    |            "sparkpost", "log", "array"
+    |            "sparkpost", "postmark", "log", "array"
     |
     */
 
@@ -122,15 +122,15 @@ return [
 
     /*
     |--------------------------------------------------------------------------
-    | 注意:仅在自建邮局且PHP5.6+时使用
+    | Log Channel
     |--------------------------------------------------------------------------
+    |
+    | If you are using the "log" driver, you may specify the logging channel
+    | if you prefer to keep mail messages separate from other log entries
+    | for simpler reading. Otherwise, the default channel will be used.
+    |
     */
-    //    'stream'   => [
-    //        'ssl' => [
-    //            'verify_peer'       => false,
-    //            'verify_peer_name'  => false,
-    //            'allow_self_signed' => false,
-    //        ],
-    //    ],
+
+    'log_channel' => env('MAIL_LOG_CHANNEL'),
 
 ];

+ 7 - 5
config/permission.php

@@ -80,6 +80,7 @@ return [
          * For example, this would be nice if your primary keys are all UUIDs. In
          * that case, name this `model_uuid`.
          */
+
         'model_morph_key' => 'model_id',
     ],
 
@@ -89,19 +90,19 @@ return [
      * the default setting is false here for optimum safety.
      */
 
-    'display_permission_in_exception' => FALSE,
+    'display_permission_in_exception' => false,
 
     'cache' => [
 
         /*
-         * By default all permissions will be cached for 24 hours unless a permission or
-         * role is updated. Then the cache will be flushed immediately.
+         * By default all permissions are cached for 24 hours to speed up performance.
+         * When permissions or roles are updated the cache is flushed automatically.
          */
 
-        'expiration_time' => 60 * 24,
+        'expiration_time' => \DateInterval::createFromDateString('24 hours'),
 
         /*
-         * The key to use when tagging and prefixing entries in the cache.
+         * The cache key used to store all permissions.
          */
 
         'key' => 'spatie.permission.cache',
@@ -122,6 +123,7 @@ return [
          * role caching using any of the `store` drivers listed in the cache.php config
          * file. Using 'default' here means to use the `default` set in cache.php.
          */
+
         'store' => 'default',
     ],
 ];

+ 7 - 6
config/queue.php

@@ -13,7 +13,7 @@ return [
     |
     */
 
-    'default' => env('QUEUE_DRIVER', 'sync'),
+    'default' => env('QUEUE_CONNECTION', 'sync'),
 
     /*
     |--------------------------------------------------------------------------
@@ -46,23 +46,24 @@ return [
             'host' => 'localhost',
             'queue' => 'default',
             'retry_after' => 90,
+            'block_for' => 0,
         ],
 
         'sqs' => [
             'driver' => 'sqs',
-            'key' => env('SQS_KEY', 'your-public-key'),
-            'secret' => env('SQS_SECRET', 'your-secret-key'),
+            'key' => env('AWS_ACCESS_KEY_ID'),
+            'secret' => env('AWS_SECRET_ACCESS_KEY'),
             'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'),
             'queue' => env('SQS_QUEUE', 'your-queue-name'),
-            'region' => env('SQS_REGION', 'us-east-1'),
+            'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
         ],
 
         'redis' => [
             'driver' => 'redis',
             'connection' => 'default',
-            'queue' => 'default',
+            'queue' => env('REDIS_QUEUE', 'default'),
             'retry_after' => 90,
-            'block_for' => NULL,
+            'block_for' => null,
         ],
 
     ],

+ 11 - 12
config/services.php

@@ -8,31 +8,30 @@ return [
     |--------------------------------------------------------------------------
     |
     | This file is for storing the credentials for third party services such
-    | as Stripe, Mailgun, SparkPost and others. This file provides a sane
-    | default location for this type of information, allowing packages
-    | to have a conventional place to find your various credentials.
+    | as Mailgun, SparkPost and others. This file provides a sane default
+    | location for this type of information, allowing packages to have
+    | a conventional file to locate the various service credentials.
     |
     */
 
     'mailgun' => [
         'domain' => env('MAILGUN_DOMAIN'),
         'secret' => env('MAILGUN_SECRET'),
+        'endpoint' => env('MAILGUN_ENDPOINT', 'api.mailgun.net'),
+    ],
+
+    'postmark' => [
+        'token' => env('POSTMARK_TOKEN'),
     ],
 
     'ses' => [
-        'key' => env('SES_KEY'),
-        'secret' => env('SES_SECRET'),
-        'region' => env('SES_REGION', 'us-east-1'),
+        'key' => env('AWS_ACCESS_KEY_ID'),
+        'secret' => env('AWS_SECRET_ACCESS_KEY'),
+        'region' => env('AWS_DEFAULT_REGION', 'us-east-1'),
     ],
 
     'sparkpost' => [
         'secret' => env('SPARKPOST_SECRET'),
     ],
 
-    'stripe' => [
-        'model' => App\User::class,
-        'key' => env('STRIPE_KEY'),
-        'secret' => env('STRIPE_SECRET'),
-    ],
-
 ];

+ 15 - 13
config/session.php

@@ -1,5 +1,7 @@
 <?php
 
+use Illuminate\Support\Str;
+
 return [
 
     /*
@@ -12,7 +14,7 @@ return [
     | you may specify any of the other wonderful drivers provided here.
     |
     | Supported: "file", "cookie", "database", "apc",
-    |            "memcached", "redis", "array"
+    |            "memcached", "redis", "dynamodb", "array"
     |
     */
 
@@ -31,7 +33,7 @@ return [
 
     'lifetime' => env('SESSION_LIFETIME', 120),
 
-    'expire_on_close' => FALSE,
+    'expire_on_close' => false,
 
     /*
     |--------------------------------------------------------------------------
@@ -44,7 +46,7 @@ return [
     |
     */
 
-    'encrypt' => FALSE,
+    'encrypt' => false,
 
     /*
     |--------------------------------------------------------------------------
@@ -70,7 +72,7 @@ return [
     |
     */
 
-    'connection' => NULL,
+    'connection' => env('SESSION_CONNECTION', null),
 
     /*
     |--------------------------------------------------------------------------
@@ -90,13 +92,13 @@ return [
     | Session Cache Store
     |--------------------------------------------------------------------------
     |
-    | When using the "apc" or "memcached" session drivers, you may specify a
-    | cache store that should be used for these sessions. This value must
-    | correspond with one of the application's configured cache stores.
+    | When using the "apc", "memcached", or "dynamodb" session drivers you may
+    | list a cache store that should be used for these sessions. This value
+    | must match with one of the application's configured cache "stores".
     |
     */
 
-    'store' => NULL,
+    'store' => env('SESSION_STORE', null),
 
     /*
     |--------------------------------------------------------------------------
@@ -124,7 +126,7 @@ return [
 
     'cookie' => env(
         'SESSION_COOKIE',
-        str_slug(env('APP_NAME', 'laravel'), '_') . '_session'
+        Str::slug(env('APP_NAME', 'laravel'), '_').'_session'
     ),
 
     /*
@@ -151,7 +153,7 @@ return [
     |
     */
 
-    'domain' => env('SESSION_DOMAIN', NULL),
+    'domain' => env('SESSION_DOMAIN', null),
 
     /*
     |--------------------------------------------------------------------------
@@ -164,7 +166,7 @@ return [
     |
     */
 
-    'secure' => env('SESSION_SECURE_COOKIE', FALSE),
+    'secure' => env('SESSION_SECURE_COOKIE', false),
 
     /*
     |--------------------------------------------------------------------------
@@ -177,7 +179,7 @@ return [
     |
     */
 
-    'http_only' => TRUE,
+    'http_only' => true,
 
     /*
     |--------------------------------------------------------------------------
@@ -192,6 +194,6 @@ return [
     |
     */
 
-    'same_site' => NULL,
+    'same_site' => null,
 
 ];

+ 4 - 1
config/view.php

@@ -28,6 +28,9 @@ return [
     |
     */
 
-    'compiled' => realpath(storage_path('framework/views')),
+    'compiled' => env(
+        'VIEW_COMPILED_PATH',
+        realpath(storage_path('framework/views'))
+    ),
 
 ];

+ 1 - 0
database/.gitignore

@@ -1 +1,2 @@
 *.sqlite
+*.sqlite-journal

+ 7 - 3
database/factories/UserFactory.php

@@ -1,5 +1,8 @@
 <?php
 
+/** @var \Illuminate\Database\Eloquent\Factory $factory */
+use App\User;
+use Illuminate\Support\Str;
 use Faker\Generator as Faker;
 
 /*
@@ -13,11 +16,12 @@ use Faker\Generator as Faker;
 |
 */
 
-$factory->define(App\User::class, function (Faker $faker) {
+$factory->define(User::class, function (Faker $faker) {
     return [
         'name' => $faker->name,
         'email' => $faker->unique()->safeEmail,
-        'password' => '$2y$10$TKh8H1.PfQx37YgCzwiKb.KjNyWgaHb9cbcoQgdIVFlYg7B77UdFm', // secret
-        'remember_token' => str_random(10),
+        'email_verified_at' => now(),
+        'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
+        'remember_token' => Str::random(10),
     ];
 });

+ 9 - 6
package.json

@@ -10,13 +10,16 @@
         "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
     },
     "devDependencies": {
-        "axios": "^0.18",
-        "bootstrap": "^4.0.0",
-        "popper.js": "^1.12",
+        "axios": "^0.19",
+        "bootstrap": "^4.1.0",
         "cross-env": "^5.1",
         "jquery": "^3.2",
-        "laravel-mix": "^2.0",
-        "lodash": "^4.17.4",
-        "vue": "^2.5.7"
+        "laravel-mix": "^4.0.7",
+        "lodash": "^4.17.13",
+        "popper.js": "^1.12",
+        "resolve-url-loader": "^2.3.1",
+        "sass": "^1.15.2",
+        "sass-loader": "^7.1.0",
+        "vue": "^2.5.17"
     }
 }

+ 6 - 6
phpunit.xml

@@ -23,11 +23,11 @@
         </whitelist>
     </filter>
     <php>
-        <env name="APP_ENV" value="testing"/>
-        <env name="BCRYPT_ROUNDS" value="4"/>
-        <env name="CACHE_DRIVER" value="array"/>
-        <env name="SESSION_DRIVER" value="array"/>
-        <env name="QUEUE_DRIVER" value="sync"/>
-        <env name="MAIL_DRIVER" value="array"/>
+        <server name="APP_ENV" value="testing"/>
+        <server name="BCRYPT_ROUNDS" value="4"/>
+        <server name="CACHE_DRIVER" value="array"/>
+        <server name="MAIL_DRIVER" value="array"/>
+        <server name="QUEUE_CONNECTION" value="sync"/>
+        <server name="SESSION_DRIVER" value="array"/>
     </php>
 </phpunit>

二進制
public/assets/images/noimage.png


二進制
public/assets/images/payment/alipay.png


二進制
public/assets/images/payment/pp-logo-150px.png


二進制
public/assets/images/payment/wechat.png


+ 5 - 0
public/web.config

@@ -1,3 +1,8 @@
+<!--
+    Rewrites requires Microsoft URL Rewrite Module for IIS
+    Download: https://www.microsoft.com/en-us/download/details.aspx?id=47337
+    Debug Help: https://docs.microsoft.com/en-us/iis/extensions/url-rewrite-module/using-failed-request-tracing-to-trace-rewrite-rules
+-->
 <configuration>
   <system.webServer>
     <rewrite>

+ 0 - 23
resources/assets/js/components/Example.vue

@@ -1,23 +0,0 @@
-<template>
-	<div class="container">
-		<div class="row">
-			<div class="col-md-8 col-md-offset-2">
-				<div class="panel panel-default">
-					<div class="panel-heading">Example Component</div>
-
-					<div class="panel-body">
-						I'm an example component!
-					</div>
-				</div>
-			</div>
-		</div>
-	</div>
-</template>
-
-<script>
-    export default {
-        mounted() {
-            console.log('Component mounted.')
-        }
-    }
-</script>

+ 0 - 23
resources/assets/js/components/ExampleComponent.vue

@@ -1,23 +0,0 @@
-<template>
-	<div class="container">
-		<div class="row justify-content-center">
-			<div class="col-md-8">
-				<div class="card card-default">
-					<div class="card-header">Example Component</div>
-
-					<div class="card-body">
-						I'm an example component.
-					</div>
-				</div>
-			</div>
-		</div>
-	</div>
-</template>
-
-<script>
-    export default {
-        mounted() {
-            console.log('Component mounted.')
-        }
-    }
-</script>

+ 14 - 3
resources/assets/js/app.js → resources/js/app.js

@@ -8,14 +8,25 @@ require('./bootstrap');
 
 window.Vue = require('vue');
 
+/**
+ * The following block of code may be used to automatically register your
+ * Vue components. It will recursively scan this directory for the Vue
+ * components and automatically register them with their "basename".
+ *
+ * Eg. ./components/ExampleComponent.vue -> <example-component></example-component>
+ */
+
+// const files = require.context('./', true, /\.vue$/i);
+// files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default));
+
+Vue.component('example-component', require('./components/ExampleComponent.vue').default);
+
 /**
  * Next, we will create a fresh Vue application instance and attach it to
  * the page. Then, you may begin adding components to this application
  * or customize the JavaScript scaffolding to fit your unique needs.
  */
 
-Vue.component('example-component', require('./components/ExampleComponent.vue'));
-
 const app = new Vue({
-    el: '#app'
+    el: '#app',
 });

+ 3 - 18
resources/assets/js/bootstrap.js → resources/js/bootstrap.js

@@ -1,5 +1,4 @@
 window._ = require('lodash');
-window.Popper = require('popper.js').default;
 
 /**
  * We'll load jQuery and the Bootstrap jQuery plugin which provides support
@@ -8,11 +7,11 @@ window.Popper = require('popper.js').default;
  */
 
 try {
+    window.Popper = require('popper.js').default;
     window.$ = window.jQuery = require('jquery');
 
     require('bootstrap');
-} catch (e) {
-}
+} catch (e) {}
 
 /**
  * We'll load the axios HTTP library which allows us to easily issue requests
@@ -24,27 +23,13 @@ window.axios = require('axios');
 
 window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
 
-/**
- * Next we will register the CSRF Token as a common header with Axios so that
- * all outgoing HTTP requests automatically have it attached. This is just
- * a simple convenience so we don't have to attach every token manually.
- */
-
-let token = document.head.querySelector('meta[name="csrf-token"]');
-
-if (token) {
-    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
-} else {
-    console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
-}
-
 /**
  * Echo exposes an expressive API for subscribing to channels and listening
  * for events that are broadcast by Laravel. Echo and event broadcasting
  * allows your team to easily build robust real-time web applications.
  */
 
-// import Echo from 'laravel-echo'
+// import Echo from 'laravel-echo';
 
 // window.Pusher = require('pusher-js');
 

+ 23 - 0
resources/js/components/ExampleComponent.vue

@@ -0,0 +1,23 @@
+<template>
+    <div class="container">
+        <div class="row justify-content-center">
+            <div class="col-md-8">
+                <div class="card">
+                    <div class="card-header">Example Component</div>
+
+                    <div class="card-body">
+                        I'm an example component.
+                    </div>
+                </div>
+            </div>
+        </div>
+    </div>
+</template>
+
+<script>
+    export default {
+        mounted() {
+            console.log('Component mounted.')
+        }
+    }
+</script>

+ 2 - 2
resources/assets/sass/_variables.scss → resources/sass/_variables.scss

@@ -2,7 +2,7 @@
 $body-bg: #f8fafc;
 
 // Typography
-$font-family-sans-serif: "Nunito", sans-serif;
+$font-family-sans-serif: 'Nunito', sans-serif;
 $font-size-base: 0.9rem;
 $line-height-base: 1.6;
 
@@ -10,7 +10,7 @@ $line-height-base: 1.6;
 $blue: #3490dc;
 $indigo: #6574cd;
 $purple: #9561e2;
-$pink: #f66D9b;
+$pink: #f66d9b;
 $red: #e3342f;
 $orange: #f6993f;
 $yellow: #ffed4a;

+ 2 - 5
resources/assets/sass/app.scss → resources/sass/app.scss

@@ -1,11 +1,8 @@
 // Fonts
 @import url('https://fonts.googleapis.com/css?family=Nunito');
+
 // Variables
 @import 'variables';
+
 // Bootstrap
 @import '~bootstrap/scss/bootstrap';
-
-.navbar-laravel {
-  background-color: #fff;
-  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.04);
-}

+ 1 - 1
resources/views/admin/article/articleList.blade.php

@@ -40,7 +40,7 @@
 							@endif
 							<td>
 								<a href="/article?id={{$vo->id}}"
-										target="_blank"> {{\Illuminate\Support\Str::limit($vo->title, 80)}} </a>
+										target="_blank"> {{Str::limit($vo->title, 80)}} </a>
 							</td>
 							<td> {{$vo->sort}} </td>
 							<td> {{$vo->created_at}} </td>

+ 39 - 0
resources/views/admin/config/system.blade.php

@@ -455,6 +455,45 @@
 											<span class="text-help offset-md-3"> 启用后,订阅信息顶部将显示过期时间、剩余流量(Quantumult有特殊效果) </span>
 										</div>
 									</div>
+									<div class="form-group col-lg-6">
+										<div class="row">
+											<label class="col-md-3 col-form-label" for="vnet_license">Vnet授权</label>
+											<div class="col-md-7">
+												<div class="input-group">
+													<input type="text" class="form-control" id="vnet_license" value="{{$vnet_license}}"/>
+													<span class="input-group-append">
+														<button class="btn btn-primary" type="button" onclick="update('vnet_license')">修改</button>
+													</span>
+												</div>
+											</div>
+										</div>
+									</div>
+									<div class="form-group col-lg-6">
+										<div class="row">
+											<label class="col-md-3 col-form-label" for="v2ray_license">V2Ray授权</label>
+											<div class="col-md-7">
+												<div class="input-group">
+													<input type="text" class="form-control" id="v2ray_license" value="{{$v2ray_license}}"/>
+													<span class="input-group-append">
+														<button class="btn btn-primary" type="button" onclick="update('v2ray_license')">修改</button>
+													</span>
+												</div>
+											</div>
+										</div>
+									</div>
+									<div class="form-group col-lg-6">
+										<div class="row">
+											<label class="col-md-3 col-form-label" for="trojan_license">Trojan授权</label>
+											<div class="col-md-7">
+												<div class="input-group">
+													<input type="text" class="form-control" id="trojan_license" value="{{$trojan_license}}"/>
+													<span class="input-group-append">
+														<button class="btn btn-primary" type="button" onclick="update('trojan_license')">修改</button>
+													</span>
+												</div>
+											</div>
+										</div>
+									</div>
 								</div>
 							</form>
 						</div>

+ 1 - 1
resources/views/admin/coupon/addCoupon.blade.php

@@ -15,7 +15,7 @@
 			<div class="panel-heading">
 				<h1 class="panel-title">生成卡券</h1>
 				<div class="panel-actions">
-					<a href="{{url('/coupon/list')}}" class="btn btn-danger">返 回</a>
+					<a href="{{url('/coupon')}}" class="btn btn-danger">返 回</a>
 				</div>
 			</div>
 			@if (Session::has('successMsg'))

+ 3 - 4
resources/views/admin/coupon/couponList.blade.php

@@ -35,7 +35,7 @@
 					</div>
 					<div class="form-group col-lg-3 col-sm-4 btn-group">
 						<button class="btn btn-primary" onclick="Search()">搜 索</button>
-						<a href="{{url('/coupon/list')}}" class="btn btn-danger">重 置</a>
+						<a href="{{url('/coupon')}}" class="btn btn-danger">重 置</a>
 					</div>
 				</div>
 				<table class="text-md-center" data-toggle="table" data-mobile-responsive="true">
@@ -116,8 +116,7 @@
 @endsection
 @section('script')
 	<script src="/assets/global/vendor/bootstrap-table/bootstrap-table.min.js" type="text/javascript"></script>
-	<script src="/assets/global/vendor/bootstrap-table/extensions/mobile/bootstrap-table-mobile.min.js"
-			type="text/javascript"></script>
+	<script src="/assets/global/vendor/bootstrap-table/extensions/mobile/bootstrap-table-mobile.min.js" type="text/javascript"></script>
 	<script type="text/javascript">
 		$(document).ready(function () {
 			$('#type').val({{Request::get('type')}});
@@ -134,7 +133,7 @@
 
 		// 搜索
 		function Search() {
-			window.location.href = '/coupon/list' + '?sn=' + $("#sn").val() + '&type=' + $("#type").val() + '&status=' + $("#status").val();
+			window.location.href = '/coupon' + '?sn=' + $("#sn").val() + '&type=' + $("#type").val() + '&status=' + $("#status").val();
 		}
 
 		// 批量导出卡券

+ 35 - 30
resources/views/admin/layouts.blade.php

@@ -120,17 +120,17 @@
 				</a>
 				<ul class="site-menu-sub">
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/userList', 'admin/addUser', 'admin/editUser', 'admin/export', 'admin/onlineIPMonitor', 'admin/userMonitor']) ? 'active open' : ''}}">
-						<a href="/admin/userList" class="animsition-link">
+						<a href="/admin/userList">
 							<span class="site-menu-title">用户管理</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/userCreditLogList']) ? 'active open' : ''}}">
-						<a href="/admin/userCreditLogList" class="animsition-link">
+						<a href="/admin/userCreditLogList">
 							<span class="site-menu-title">余额变动</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['subscribe']) ? 'active open' : ''}}">
-						<a href="/subscribe" class="animsition-link">
+						<a href="/subscribe">
 							<span class="site-menu-title">订阅管理</span>
 						</a>
 					</li>
@@ -148,7 +148,7 @@
 				</a>
 				<ul class="site-menu-sub">
 					<li class="site-menu-item {{in_array(Request::path(), ['ticket', 'ticket/add','ticket/reply']) ? 'active open' : ''}}">
-						<a href="/ticket" class="animsition-link">
+						<a href="/ticket">
 							<span class="site-menu-title">服务工单</span>
 							@if(\App\Models\Ticket::query()->whereStatus(0)->count() > 0 )
 								<div class="site-menu-label">
@@ -158,17 +158,17 @@
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/articleList', 'admin/addArticle', 'admin/editArticle']) ? 'active open' : ''}}">
-						<a href="/admin/articleList" class="animsition-link">
+						<a href="/admin/articleList">
 							<span class="site-menu-title">文章管理</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['marketing/push']) ? 'active open' : ''}}">
-						<a href="/marketing/push" class="animsition-link">
+						<a href="/marketing/push">
 							<span class="site-menu-title">消息推送</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['marketing/email']) ? 'active open' : ''}}">
-						<a href="/marketing/email" class="animsition-link">
+						<a href="/marketing/email">
 							<span class="site-menu-title">邮件群发</span>
 						</a>
 					</li>
@@ -181,10 +181,15 @@
 				</a>
 				<ul class="site-menu-sub">
 					<li class="site-menu-item {{in_array(Request::path(), ['node', 'node/add', 'node/edit', 'node/monitor']) ? 'active open' : ''}}">
-						<a href="/node" class="animsition-link">
+						<a href="/node">
 							<span class="site-menu-title">线路管理</span>
 						</a>
 					</li>
+					<li class="site-menu-item {{in_array(Request::path(), ['node/auth', 'node/auth/add', 'node/auth/delete', 'node/auth/refresh']) ? 'active open' : ''}}">
+						<a href="/node/auth">
+							<span class="site-menu-title">线路授权</span>
+						</a>
+					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['node/pingLog']) ? 'active open' : ''}}">
 						<a href="/node/pingLog">
 							<span class="site-menu-title">测速日志</span>
@@ -199,7 +204,7 @@
 				</a>
 				<ul class="site-menu-sub">
 					<li class="site-menu-item {{in_array(Request::path(), ['rule', 'rule/add', 'rule/edit']) ? 'active open' : ''}}">
-						<a href="/rule" class="animsition-link">
+						<a href="/rule">
 							<span class="site-menu-title">规则列表</span>
 						</a>
 					</li>
@@ -222,17 +227,17 @@
 				</a>
 				<ul class="site-menu-sub">
 					<li class="site-menu-item {{in_array(Request::path(), ['shop', 'shop/add', 'shop/edit']) ? 'active open' : ''}}">
-						<a href="/shop" class="animsition-link">
+						<a href="/shop">
 							<span class="site-menu-title">商品管理</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['coupon', 'coupon/add']) ? 'active open' : ''}}">
-						<a href="/coupon" class="animsition-link">
+						<a href="/coupon">
 							<span class="site-menu-title">卡券管理</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/orderList']) ? 'active open' : ''}}">
-						<a href="/admin/orderList" class="animsition-link">
+						<a href="/admin/orderList">
 							<span class="site-menu-title">商品订单</span>
 						</a>
 					</li>
@@ -250,12 +255,12 @@
 				</a>
 				<ul class="site-menu-sub">
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/inviteList']) ? 'active open' : ''}}">
-						<a href="/admin/inviteList" class="animsition-link">
+						<a href="/admin/inviteList">
 							<span class="site-menu-title">邀请管理</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/affList', 'admin/affDetail']) ? 'active open' : ''}}">
-						<a href="/admin/affList" class="animsition-link">
+						<a href="/admin/affList">
 							<span class="site-menu-title">提现管理</span>
 							@if(\App\Models\ReferralApply::query()->whereStatus(0)->count() > 0 )
 								<div class="site-menu-label">
@@ -265,7 +270,7 @@
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/userRebateList']) ? 'active open' : ''}}">
-						<a href="/admin/userRebateList" class="animsition-link">
+						<a href="/admin/userRebateList">
 							<span class="site-menu-title">返利流水</span>
 						</a>
 					</li>
@@ -278,42 +283,42 @@
 				</a>
 				<ul class="site-menu-sub">
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/trafficLog']) ? 'active open' : ''}}">
-						<a href="/admin/trafficLog" class="animsition-link">
+						<a href="/admin/trafficLog">
 							<span class="site-menu-title">流量使用</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/userTrafficLogList']) ? 'active open' : ''}}">
-						<a href="/admin/userTrafficLogList" class="animsition-link">
+						<a href="/admin/userTrafficLogList">
 							<span class="site-menu-title">流量变动</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/userBanLogList']) ? 'active open' : ''}}">
-						<a href="/admin/userBanLogList" class="animsition-link">
+						<a href="/admin/userBanLogList">
 							<span class="site-menu-title">封禁记录</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/userOnlineIPList']) ? 'active open' : ''}}">
-						<a href="/admin/userOnlineIPList" class="animsition-link">
+						<a href="/admin/userOnlineIPList">
 							<span class="site-menu-title">在线记录</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/onlineIPMonitor']) ? 'active open' : ''}}">
-						<a href="/admin/onlineIPMonitor" class="animsition-link">
+						<a href="/admin/onlineIPMonitor">
 							<span class="site-menu-title">在线监控</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/notificationLog']) ? 'active open' : ''}}">
-						<a href="/admin/notificationLog" class="animsition-link">
+						<a href="/admin/notificationLog">
 							<span class="site-menu-title">通知记录</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['payment/callbackList']) ? 'active open' : ''}}">
-						<a href="/payment/callbackList" class="animsition-link">
+						<a href="/payment/callbackList">
 							<span class="site-menu-title">支付回调</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['logs']) ? 'active open' : ''}}">
-						<a href="/logs" class="animsition-link" target="_blank">
+						<a href="/logs" target="_blank">
 							<span class="site-menu-title">系统运行</span>
 						</a>
 					</li>
@@ -326,22 +331,22 @@
 				</a>
 				<ul class="site-menu-sub">
 					<li class="site-menu-item {{in_array(Request::path(), ['tools/decompile']) ? 'active open' : ''}}">
-						<a href="/tools/decompile" class="animsition-link">
+						<a href="/tools/decompile">
 							<span class="site-menu-title">反解析</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['tools/convert']) ? 'active open' : ''}}">
-						<a href="/tools/convert" class="animsition-link">
+						<a href="/tools/convert">
 							<span class="site-menu-title">格式转换</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['tools/import']) ? 'active open' : ''}}">
-						<a href="/tools/import" class="animsition-link">
+						<a href="/tools/import">
 							<span class="site-menu-title">数据导入</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['tools/analysis']) ? 'active open' : ''}}">
-						<a href="/tools/analysis" class="animsition-link">
+						<a href="/tools/analysis">
 							<span class="site-menu-title">日志分析</span>
 						</a>
 					</li>
@@ -354,17 +359,17 @@
 				</a>
 				<ul class="site-menu-sub">
 					<li class="site-menu-item {{in_array(Request::path(), ['sensitiveWords']) ? 'active open' : ''}}">
-						<a href="/sensitiveWords" class="animsition-link">
+						<a href="/sensitiveWords">
 							<span class="site-menu-title">敏感词管理</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/config']) ? 'active open' : ''}}">
-						<a href="/admin/config" class="animsition-link">
+						<a href="/admin/config">
 							<span class="site-menu-title">通用配置</span>
 						</a>
 					</li>
 					<li class="site-menu-item {{in_array(Request::path(), ['admin/system']) ? 'active open' : ''}}">
-						<a href="/admin/system" class="animsition-link">
+						<a href="/admin/system">
 							<span class="site-menu-title">系统设置</span>
 						</a>
 					</li>

+ 1 - 2
resources/views/admin/logs/notificationLog.blade.php

@@ -54,8 +54,7 @@
 							<td> {{$vo->created_at}} </td>
 							<td>
 								@if($vo->status < 0)
-									<span
-											class="badge badge-danger"> {{\Illuminate\Support\Str::limit($vo->error)}} </span>
+									<span class="badge badge-danger"> {{Str::limit($vo->error)}} </span>
 								@elseif($vo->status > 0)
 									<labe class="badge badge-success">投递成功</labe>
 								@else

+ 5 - 7
resources/views/admin/logs/onlineIPMonitor.blade.php

@@ -7,7 +7,7 @@
 		<div class="panel">
 			<div class="panel-heading">
 				<h3 class="panel-title">在线IP监控
-					<small>实时</small>
+					<small>2分钟内的实时数据</small>
 				</h3>
 			</div>
 			<div class="panel-body">
@@ -46,26 +46,23 @@
 					<thead class="thead-default">
 					<tr>
 						<th> #</th>
-						<th> 时间</th>
 						<th> 类型</th>
 						<th> 节点</th>
 						<th> 用户</th>
-						<th> 地址</th>
 						<th> IP</th>
 						<th> 归属地</th>
+						<th> 时间</th>
 					</tr>
 					</thead>
 					<tbody>
 					@foreach($list as $vo)
 						<tr>
 							<td>{{$vo->id}}</td>
-							<td>{{$vo->created_at}}</td>
 							<td>{{$vo->type}}</td>
 							<td>{{$vo->node ? $vo->node->name : '【节点已删除】'}}</td>
 							<td>{{$vo->user ? $vo->user->email : '【用户已删除】'}}</td>
-							<td>{{$vo->user ? $vo->user->address : '【用户已删除】'}}</td>
 							<td>
-								@if (strpos($vo->ip, ',') == TRUE)
+								@if (strpos($vo->ip, ',') == true)
 									@foreach (explode(',', $vo->ip) as $ip)
 										<a href="https://www.ipip.net/ip/{{$ip}}.html" target="_blank">{{$ip}}</a>
 									@endforeach
@@ -73,7 +70,8 @@
 									<a href="https://www.ipip.net/ip/{{$vo->ip}}.html" target="_blank">{{$vo->ip}}</a>
 								@endif
 							</td>
-							<td>{{strpos($vo->ip, ',') == TRUE? '':$vo->ipInfo}}</td>
+							<td>{{strpos($vo->ip, ',') == true? '':$vo->ipInfo}}</td>
+							<td>{{date('Y-m-d H:i:s',$vo->created_at)}}</td>
 						</tr>
 					@endforeach
 					</tbody>

+ 280 - 0
resources/views/admin/node/authList.blade.php

@@ -0,0 +1,280 @@
+@extends('admin.layouts')
+@section('css')
+	<link href="/assets/global/vendor/bootstrap-table/bootstrap-table.min.css" type="text/css" rel="stylesheet">
+@endsection
+@section('content')
+	<div class="page-content container-fluid">
+		<div class="panel">
+			<div class="panel-heading">
+				<h2 class="panel-title">节点授权列表<small>WEBAPI</small></h2>
+				<div class="panel-actions">
+					<button class="btn btn-outline-default" onclick="addAuth()">
+						<i class="icon wb-plus" aria-hidden="true"></i>生成授权
+					</button>
+				</div>
+			</div>
+			<div class="panel-body">
+				<table class="text-md-center" data-toggle="table" data-mobile-responsive="true">
+					<thead class="thead-default">
+					<tr>
+						<th> #</th>
+						<th> 节点ID</th>
+						<th> 节点类型</th>
+						<th> 节点名称</th>
+						<th> 节点域名</th>
+						<th> IPv4</th>
+						<th> 通信密钥<small>节点用</small></th>
+						<th> 反向通信密钥</th>
+						<th> 操作</th>
+					</tr>
+					</thead>
+					<tbody>
+					@foreach ($list as $vo)
+						<tr>
+							<td> {{$vo->id}} </td>
+							<td> {{$vo->node_id}} </td>
+							<td> {{$vo->node->type_label}} </td>
+							<td> {{$vo->node ? Str::limit($vo->node->name, 20) : '【节点已删除】'}} </td>
+							<td> {{$vo->node ? $vo->node->server : '【节点已删除】'}} </td>
+							<td> {{$vo->node ? $vo->node->ip : '【节点已删除】'}} </td>
+							<td><span class="badge badge-lg badge-info"> {{$vo->key}} </span></td>
+							<td><span class="badge badge-lg badge-info"> {{$vo->secret}} </span></td>
+							<td>
+								<div class="btn-group">
+									<button data-target="#install_{{$vo->node->type}}_{{$vo->id}}" data-toggle="modal" class="btn btn-primary">
+										<i class="icon wb-code" aria-hidden="true"></i>部署后端
+									</button>
+									<button onclick="refreshAuth('{{$vo->id}}')" class="btn btn-danger">
+										<i class="icon wb-reload" aria-hidden="true"></i> 重置密钥
+									</button>
+									<button onclick="deleteAuth('{{$vo->id}}')" class="btn btn-primary">
+										<i class="icon wb-trash" aria-hidden="true"></i> 删除
+									</button>
+								</div>
+							</td>
+						</tr>
+					@endforeach
+					</tbody>
+				</table>
+			</div>
+			<div class="panel-footer">
+				<div class="row">
+					<div class="col-sm-4">
+						共 <code>{{$list->total()}}</code> 条授权
+					</div>
+					<div class="col-sm-8">
+						<nav class="Page navigation float-right">
+							{{$list->links()}}
+						</nav>
+					</div>
+				</div>
+			</div>
+		</div>
+	</div>
+
+	@foreach($list as $vl)
+		<div id="install_{{$vl->node->type}}_{{$vl->id}}" class="modal fade" tabindex="-1" data-focus-on="input:first" data-keyboard="false">
+			<div class="modal-dialog modal-simple modal-center modal-lg">
+				<div class="modal-content">
+					<div class="modal-header">
+						<button type="button" class="close" data-dismiss="modal" aria-label="Close">
+							<span aria-hidden="true">×</span>
+						</button>
+						<h4 class="modal-title">
+							部署 {{$vl->node->type_label}} 后端
+						</h4>
+					</div>
+					<div class="modal-body">
+						@if($vl->node->type == '2')
+							<div class="alert alert-info  text-break">
+								<div class="text-center red-700 mb-5">VNET-V2Ray</div>
+								(yum install curl 2> /dev/null || apt install curl 2> /dev/null) \<br>
+								&& curl -L -s https://bit.ly/2xoemF2 \<br>
+								| WEB_API="{{\App\Components\Helpers::systemConfig()['vnet_license'] ?: \App\Components\Helpers::systemConfig()['website_url']}}" \<br>
+								NODE_ID={{$vl->node->id}} \<br>
+								NODE_KEY={{$vl->key}} \<br>
+								bash
+								<br>
+								<br>
+								<div class="text-center red-700 mb-5">操作命令</div>
+								更新:同上
+								<br>
+								卸载:curl -L -s https://bit.ly/2xoemF2 | bash -s -- --remove
+								<br>
+								启动:systemctl start vnet-v2ray
+								<br>
+								停止:systemctl stop vnet-v2ray
+								<br>
+								状态:systemctl status vnet-v2ray
+								<br>
+								近期日志:journalctl -x -n 300 --no-pager -u vnet-v2ray
+								<br>
+								实时日志:journalctl -u vnet-v2ray -f
+							</div>
+							<div class="alert alert-info text-break">
+								<div class="text-center red-700 mb-5">V2Ray-Poseidon</div>
+								(yum install curl 2> /dev/null || apt install curl 2> /dev/null) \<br>
+								&& curl -L -s https://bit.ly/2VhvcPz \<br>
+								| WEB_API="{{\App\Components\Helpers::systemConfig()['vnet_license'] ?: \App\Components\Helpers::systemConfig()['website_url']}}" \<br>
+								NODE_ID={{$vl->node->id}} \<br>
+								NODE_KEY={{$vl->key}} \<br>
+								bash
+								<br>
+								<br>
+								<div class="text-center red-700 mb-5">操作命令</div>
+								更新:curl -L -s https://bit.ly/2VhvcPz | bash
+								<br>
+								卸载:curl -L -s https://bit.ly/2SGFMMY | bash
+								<br>
+								启动:systemctl start v2ray
+								<br>
+								停止:systemctl stop v2ray
+								<br>
+								状态:systemctl status v2ray
+								<br>
+								近期日志:journalctl -x -n 300 --no-pager -u v2ray
+								<br>
+								实时日志:journalctl -u v2ray -f
+							</div>
+						@elseif($vl->node->type == '3')
+							@if(!$vl->node->server)
+								<h3>请先<a href="/node/edit?id={{$vl->node->id}}" target="_blank">填写节点域名</a>并将域名解析到节点对应的IP上</h3>
+							@else
+								<div class="alert alert-info text-break">
+									<div class="text-center red-700 mb-5">Trojan-Poseidon</div>
+									(yum install curl 2> /dev/null || apt install curl 2> /dev/null) \<br>
+									&& curl -L -s https://bit.ly/33UdELu \<br>
+									| WEB_API="{{\App\Components\Helpers::systemConfig()['v2ray_license'] ?: \App\Components\Helpers::systemConfig()['website_url']}}" \<br>
+									NODE_ID={{$vl->node->id}} \<br>
+									NODE_KEY={{$vl->key}} \<br>
+									NODE_HOST={{$vl->node->server}} \<br>
+									bash
+									<br>
+									<br>
+									<div class="text-center red-700 mb-5">操作命令</div>
+									更新:curl -L -s https://bit.ly/33UdELu | bash
+									<br>
+									卸载:curl -L -s https://bit.ly/2Jl9bs7 | bash
+									<br>
+									启动:systemctl start trojanp
+									<br>
+									停止:systemctl stop trojanp
+									<br>
+									状态:systemctl status trojanp
+									<br>
+									近期日志:journalctl -x -n 300 --no-pager -u trojanp
+									<br>
+									实时日志:journalctl -u trojanp -f
+								</div>
+							@endif
+						@else
+							<div class="alert alert-info text-break">
+								<div class="text-center red-700 mb-5">VNET</div>
+								(yum install curl 2> /dev/null || apt install curl 2> /dev/null) \<br>
+								&& curl -L -s https://bit.ly/2RNkPk7 \<br>
+								| WEB_API="{{\App\Components\Helpers::systemConfig()['vnet_license'] ?: \App\Components\Helpers::systemConfig()['website_url']}}" \<br>
+								NODE_ID={{$vl->node->id}} \<br>
+								NODE_KEY={{$vl->key}} \<br>
+								bash
+								<br>
+								<br>
+								<div class="text-center red-700 mb-5">操作命令</div>
+								更新:同上
+								<br>
+								卸载:curl -L -s https://bit.ly/2RNkPk7 | bash -s -- --remove
+								<br>
+								启动:systemctl start vnet
+								<br>
+								停止:systemctl stop vnet
+								<br>
+								重启:systemctl restart vnet
+								<br>
+								状态:systemctl status vnet
+								<br>
+								近期日志:journalctl -x -n 300 --no-pager -u vnet
+								<br>
+								实时日志:journalctl -u vnet -f
+							</div>
+						@endif
+					</div>
+				</div>
+			</div>
+		</div>
+	@endforeach
+
+@endsection
+@section('script')
+	<script src="/assets/global/vendor/bootstrap-table/bootstrap-table.min.js" type="text/javascript"></script>
+	<script src="/assets/global/vendor/bootstrap-table/extensions/mobile/bootstrap-table-mobile.min.js" type="text/javascript"></script>
+
+	<script type="text/javascript">
+		// 生成授权KEY
+		function addAuth() {
+			swal.fire({
+				title: '提示',
+				text: '确定生成所有节点的授权吗?',
+				type: 'info',
+				showCancelButton: true,
+				cancelButtonText: '{{trans('home.ticket_close')}}',
+				confirmButtonText: '{{trans('home.ticket_confirm')}}',
+			}).then((result) => {
+				if (result.value) {
+					$.post("/node/auth/add", {_token: '{{csrf_token()}}'}, function (ret) {
+						if (ret.status === 'success') {
+							swal.fire({title: ret.message, type: 'success', timer: 1000, showConfirmButton: false})
+								.then(() => window.location.reload())
+						} else {
+							swal.fire({title: ret.message, type: "error"}).then(() => window.location.reload())
+						}
+					});
+				}
+			});
+		}
+
+		// 删除授权
+		function deleteAuth(id) {
+			swal.fire({
+				title: '提示',
+				text: '确定删除该授权吗?',
+				type: 'info',
+				showCancelButton: true,
+				cancelButtonText: '{{trans('home.ticket_close')}}',
+				confirmButtonText: '{{trans('home.ticket_confirm')}}',
+			}).then((result) => {
+				if (result.value) {
+					$.post("/node/auth/delete", {_token: '{{csrf_token()}}', id: id}, function (ret) {
+						if (ret.status === 'success') {
+							swal.fire({title: ret.message, type: 'success', timer: 1000, showConfirmButton: false})
+								.then(() => window.location.reload())
+						} else {
+							swal.fire({title: ret.message, type: "error"}).then(() => window.location.reload())
+						}
+					});
+				}
+			});
+		}
+
+		// 重置授权认证KEY
+		function refreshAuth(id) {
+			swal.fire({
+				title: '提示',
+				text: '确定继续操作吗?',
+				type: 'info',
+				showCancelButton: true,
+				cancelButtonText: '{{trans('home.ticket_close')}}',
+				confirmButtonText: '{{trans('home.ticket_confirm')}}',
+			}).then((result) => {
+				if (result.value) {
+					$.post("/node/auth/refresh", {_token: '{{csrf_token()}}', id: id}, function (ret) {
+						if (ret.status === 'success') {
+							swal.fire({title: ret.message, type: 'success', timer: 1000, showConfirmButton: false})
+								.then(() => window.location.reload())
+						} else {
+							swal.fire({title: ret.message, type: "error"}).then(() => window.location.reload())
+						}
+					});
+				}
+			});
+		}
+	</script>
+@endsection

+ 12 - 35
resources/views/admin/node/nodeInfo.blade.php

@@ -57,10 +57,9 @@
 												placeholder="服务器IPv6地址,填写则用户可见,域名无效">
 									</div>
 									<div class="form-group row">
-										<label for="ssh_port" class="col-md-3 col-form-label"> SSH端口 </label>
-										<input type="number" class="form-control col-md-4" name="ssh_port" value="22"
-												id="ssh_port" placeholder="服务器SSH端口">
-										<span class="text-help offset-md-3">请务必正确填写此值,否则TCP阻断检测可能误报</span>
+										<label for="push_port" class="col-md-3 col-form-label"> 消息推送端口 </label>
+										<input type="number" class="form-control col-md-4" name="push_port" value="0" id="push_port">
+										<span class="text-help offset-md-3">必填且防火墙需放行,否则将导致消息推送异常</span>
 									</div>
 									<div class="form-group row">
 										<label for="traffic_rate" class="col-md-3 col-form-label"> 流量比例 </label>
@@ -290,19 +289,12 @@
 												<input type="checkbox" id="v2_tls" name="v2_tls" data-plugin="switchery" onchange="switchSetting('v2_tls')">
 											</div>
 										</div>
-										<!-- V2Ray tls设置 -->
-										<div class="v2_tls_setting hidden">
-											<div class="form-group row">
-												<label for="v2_tls_insecure" class="col-md-3 col-form-label">是否允许不安全连接</label>
-												<div class="col-md-9">
-													<input type="checkbox" id="v2_tls_insecure" name="v2_tls_insecure" data-plugin="switchery">
-												</div>
-											</div>
-											<div class="form-group row">
-												<label for="v2_tls_insecure_ciphers" class="col-md-3 col-form-label">是否允许不安全的加密方式</label>
-												<div class="col-md-9">
-													<input type="checkbox" id="v2_tls_insecure_ciphers" name="v2_tls_insecure_ciphers" data-plugin="switchery">
-												</div>
+										<div class="form-group row">
+											<label for="tls_provider" class="col-md-3 col-form-label">TLS配置</label>
+											<input type="text" class="form-control col-md-9" name="tls_provider" id="tls_provider" required/>
+											<div class="text-help offset-md-3"> 不同后端配置不同:
+												<a href="https://github.com/Scyllaly/docs/wiki/tls" target="_blank">VNET-V2Ray</a> 、
+												<a href="https://github.com/ColetteContreras/v2ray-poseidon/wiki/020-%E5%AF%B9%E6%8E%A5-VNetPanel-%E6%95%99%E7%A8%8B#%E9%85%8D%E7%BD%AE-tls-%E8%AF%81%E4%B9%A6" target="_blank">V2Ray-Poseidon</a>
 											</div>
 										</div>
 									</div>
@@ -386,7 +378,7 @@
 	<script src="/assets/global/js/Plugin/switchery.js" type="text/javascript"></script>
 
 	<script type="text/javascript">
-		const string = "{{strtolower(\Illuminate\Support\Str::random())}}";
+		const string = "{{strtolower(Str::random())}}";
 		$(document).ready(function () {
 			const v2_path = $('#v2_path');
 
@@ -399,7 +391,7 @@
 			$('#server').val('{{$node->server}}');
 			$('#ip').val('{{$node->ip}}');
 			$('#ipv6').val('{{$node->ipv6}}');
-			$('#ssh_port').val('{{$node->ssh_port}}');
+			$('#push_port').val('{{$node->push_port}}');
 			$('#traffic_rate').val('{{$node->traffic_rate}}');
 			$('#level').selectpicker('val', '{{$node->level}}');
 			$('#speed_limit').val('{{$node->speed_limit}}');
@@ -448,12 +440,6 @@
 			v2_path.val('{{$node->v2_path}}');
 			@if($node->v2_tls)
 			$('#v2_tls').click();
-			@if($node->v2_tls_insecure)
-			$('#v2_tls_insecure').click();
-			@endif
-			@if($node->v2_tls_insecure_ciphers)
-			$('#v2_tls_insecure_ciphers').click();
-			@endif
 			@endif
 			@endif
 
@@ -483,7 +469,7 @@
 					server: $('#server').val(),
 					ip: $('#ip').val(),
 					ipv6: $('#ipv6').val(),
-					ssh_port: $('#ssh_port').val(),
+					push_port: $('#push_port').val(),
 					traffic_rate: $('#traffic_rate').val(),
 					level: $('#level').val(),
 					speed_limit: $('#speed_limit').val(),
@@ -514,8 +500,6 @@
 					v2_host: $('#v2_host').val(),
 					v2_path: $('#v2_path').val(),
 					v2_tls: document.getElementById("v2_tls").checked ? 1 : 0,
-					v2_tls_insecure: document.getElementById("v2_tls_insecure").checked ? 1 : 0,
-					v2_tls_insecure_ciphers: document.getElementById("v2_tls_insecure_ciphers").checked ? 1 : 0,
 					is_relay: document.getElementById("is_relay").checked ? 1 : 0,
 					relay_port: $('#relay_port').val(),
 					relay_server: $('#relay_server').val(),
@@ -548,13 +532,6 @@
 						$(".single-setting").hide();
 					}
 					break;
-				case 'v2_tls':
-					if (check) {
-						$(".v2_tls_setting").show();
-					} else {
-						$(".v2_tls_setting").hide();
-					}
-					break;
 				//设置中转
 				case 'is_relay':
 					if (check) {

+ 2 - 2
resources/views/admin/node/nodeList.blade.php

@@ -109,8 +109,8 @@
 		function checkNode(id) {
 			$.ajax({
 				type: "POST",
-				url: '/node/check/' + id,
-				data: {_token: '{{csrf_token()}}'},
+				url: '/node/check',
+				data: {_token: '{{csrf_token()}}', id: id},
 				beforeSend: function () {
 					$("#node" + id).removeClass("wb-signal").addClass("wb-loop icon-spin");
 				},

+ 2 - 2
resources/views/admin/rule/assignNode.blade.php

@@ -45,7 +45,7 @@
 							</div>
 							<select class="form-control" name="nodes[]" id="nodes" data-plugin="multiSelect" multiple>
 								@foreach($nodeList as $node)
-									<option value="{{$node->id}}">{{$node->id . ' - ' . \Illuminate\Support\Str::limit($node->name, 30)}}</option>
+									<option value="{{$node->id}}">{{$node->id . ' - ' . Str::limit($node->name, 30)}}</option>
 								@endforeach
 							</select>
 						</div>
@@ -64,7 +64,7 @@
 	<script src="/assets/global/js/jquery.quicksearch.js" type="text/javascript"></script>
 	<script type="text/javascript">
 		$(document).ready(function () {
-			$('#nodes').multiSelect('select',{!! json_encode(explode(', ', $ruleGroup->nodes)) !!});
+			$('#nodes').multiSelect('select',{!! json_encode(explode(',', $ruleGroup->nodes)) !!});
 		})
 
 		// 权限列表

+ 1 - 1
resources/views/admin/rule/ruleGroupInfo.blade.php

@@ -89,7 +89,7 @@
 		$(document).ready(function () {
 			$('#name').val('{{$ruleGroup->name}}');
 			$("input[name='type'][value='{{$ruleGroup->type}}']").click();
-			$('#rules').multiSelect('select',{!! json_encode(explode(', ', $ruleGroup->rules)) !!});
+			$('#rules').multiSelect('select',{!! json_encode(explode(',', $ruleGroup->rules)) !!});
 		})
 		@endisset
 		// 权限列表

+ 1 - 1
resources/views/admin/rule/ruleGroupList.blade.php

@@ -77,7 +77,7 @@
 				confirmButtonText: '{{trans('home.ticket_confirm')}}',
 			}).then((result) => {
 				if (result.value) {
-					$.post("/rule/group/delete/" + id, {_token: '{{csrf_token()}}'}, function (ret) {
+					$.post("/rule/group/delete", {_token: '{{csrf_token()}}', id: id}, function (ret) {
 						if (ret.status === 'success') {
 							swal.fire({title: ret.message, type: 'success', timer: 1000, showConfirmButton: false})
 								.then(() => window.location.reload())

+ 1 - 1
resources/views/admin/rule/ruleList.blade.php

@@ -176,7 +176,7 @@
 				confirmButtonText: '{{trans('home.ticket_confirm')}}',
 			}).then((result) => {
 				if (result.value) {
-					$.post("/rule/delete/" + id, {_token: '{{csrf_token()}}'}, function (ret) {
+					$.post("/rule/delete", {_token: '{{csrf_token()}}', id: id}, function (ret) {
 						if (ret.status === 'success') {
 							swal.fire({title: ret.message, type: 'success', timer: 1000, showConfirmButton: false})
 								.then(() => window.location.reload())

+ 1 - 2
resources/views/admin/subscribe/subscribeList.blade.php

@@ -97,8 +97,7 @@
 @endsection
 @section('script')
 	<script src="/assets/global/vendor/bootstrap-table/bootstrap-table.min.js" type="text/javascript"></script>
-	<script src="/assets/global/vendor/bootstrap-table/extensions/mobile/bootstrap-table-mobile.min.js"
-			type="text/javascript"></script>
+	<script src="/assets/global/vendor/bootstrap-table/extensions/mobile/bootstrap-table-mobile.min.js" type="text/javascript"></script>
 	<script type="text/javascript">
 		$(document).ready(function () {
 			$('#status').val({{Request::get('status')}});

+ 38 - 32
resources/views/admin/user/userList.blade.php

@@ -23,24 +23,19 @@
 			<div class="panel-body">
 				<div class="form-row">
 					<div class="form-group col-xxl-1 col-lg-1 col-md-1 col-sm-4">
-						<input type="number" class="form-control" id="id" name="id" value="{{Request::get('id')}}"
-								placeholder="ID"/>
+						<input type="number" class="form-control" id="id" name="id" value="{{Request::get('id')}}" placeholder="ID"/>
 					</div>
 					<div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">
-						<input type="text" class="form-control" id="email" name="email"
-								value="{{Request::get('email')}}" placeholder="用户名"/>
+						<input type="text" class="form-control" id="email" name="email" value="{{Request::get('email')}}" placeholder="用户名"/>
 					</div>
 					<div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">
-						<input type="text" class="form-control" id="wechat" name="wechat"
-								value="{{Request::get('wechat')}}" placeholder="微信"/>
+						<input type="text" class="form-control" id="wechat" name="wechat" value="{{Request::get('wechat')}}" placeholder="微信"/>
 					</div>
 					<div class="form-group col-xxl-2 col-lg-3 col-md-3 col-sm-4">
-						<input type="number" class="form-control" id="qq" name="qq" value="{{Request::get('qq')}}"
-								placeholder="QQ"/>
+						<input type="number" class="form-control" id="qq" name="qq" value="{{Request::get('qq')}}" placeholder="QQ"/>
 					</div>
 					<div class="form-group col-xxl-1 col-lg-2 col-md-2 col-sm-4">
-						<input type="number" class="form-control" id="port" name="port" value="{{Request::get('port')}}"
-								placeholder="端口"/>
+						<input type="number" class="form-control" id="port" name="port" value="{{Request::get('port')}}" placeholder="端口"/>
 					</div>
 					<div class="form-group col-xxl-1 col-lg-3 col-md-3 col-4">
 						<select class="form-control" id="status" name="status" onChange="Search()">
@@ -106,36 +101,47 @@
 							</td>
 							<td>
 								@if ($user->status > 0)
-									<span class="badge badge-lg badge-primary"><i class="wb-check"
-												aria-hidden="true"></i></span>
+									<span class="badge badge-lg badge-primary">
+										<i class="wb-check" aria-hidden="true"></i>
+									</span>
 								@elseif ($user->status < 0)
-									<span class="badge badge-lg badge-danger"><i class="wb-close"
-												aria-hidden="true"></i></span>
+									<span class="badge badge-lg badge-danger">
+										<i class="wb-close" aria-hidden="true"></i>
+									</span>
 								@else
-									<span class="badge badge-lg badge-default"><i class="wb-minus"
-												aria-hidden="true"></i></span>
+									<span class="badge badge-lg badge-default">
+										<i class="wb-minus" aria-hidden="true"></i>
+									</span>
 								@endif
 							</td>
 							<td>
-								<span class="badge badge-lg badge-{{$user->enable?'info':'danger'}}"><i
-											class="wb-{{$user->enable?'check':'close'}}" aria-hidden="true"></i></span>
+								<span class="badge badge-lg badge-{{$user->enable?'info':'danger'}}">
+									<i class="wb-{{$user->enable?'check':'close'}}" aria-hidden="true"></i>
+								</span>
 							</td>
 							<td>
 								<div class="btn-group">
-									<a href="/admin/editUser/{{$user->id}}{{Request::getQueryString()? '?'.Request::getQueryString() : ''}}"
-											class="btn btn-primary"><i class="icon wb-edit" aria-hidden="true"></i></a>
-									<a href="javascript:delUser('{{$user->id}}','{{$user->email}}');"
-											class="btn btn-danger"><i class="icon wb-trash" aria-hidden="true"></i></a>
-									<a href="/admin/export/{{$user->id}}" class="btn btn-primary"><i
-												class="icon wb-code" aria-hidden="true"></i></a>
-									<a href="/admin/userMonitor/{{$user->id}}" class="btn btn-primary"><i
-												class="icon wb-stats-bars" aria-hidden="true"></i></a>
-									<a href="/admin/onlineIPMonitor?id={{$user->id}}" class="btn btn-primary"><i
-												class="icon wb-cloud" aria-hidden="true"></i></a>
-									<a href="javascript:resetTraffic('{{$user->id}}','{{$user->email}}');"
-											class="btn btn-primary"><i class="icon wb-reload" aria-hidden="true"></i></a>
-									<a href="javascript:switchToUser('{{$user->id}}');" class="btn btn-primary"><i
-												class="icon wb-user" aria-hidden="true"></i></a>
+									<a href="/admin/editUser/{{$user->id}}{{Request::getQueryString()? '?'.Request::getQueryString() : ''}}" class="btn btn-primary">
+										<i class="icon wb-edit" aria-hidden="true"></i>
+									</a>
+									<a href="javascript:delUser('{{$user->id}}','{{$user->email}}');" class="btn btn-danger">
+										<i class="icon wb-trash" aria-hidden="true"></i>
+									</a>
+									<a href="/admin/export/{{$user->id}}" class="btn btn-primary">
+										<i class="icon wb-code" aria-hidden="true"></i>
+									</a>
+									<a href="/admin/userMonitor/{{$user->id}}" class="btn btn-primary">
+										<i class="icon wb-stats-bars" aria-hidden="true"></i>
+									</a>
+									<a href="/admin/onlineIPMonitor?id={{$user->id}}" class="btn btn-primary">
+										<i class="icon wb-cloud" aria-hidden="true"></i>
+									</a>
+									<a href="javascript:resetTraffic('{{$user->id}}','{{$user->email}}');" class="btn btn-primary">
+										<i class="icon wb-reload" aria-hidden="true"></i>
+									</a>
+									<a href="javascript:switchToUser('{{$user->id}}');" class="btn btn-primary">
+										<i class="icon wb-user" aria-hidden="true"></i>
+									</a>
 								</div>
 							</td>
 						</tr>

+ 2 - 2
resources/views/user/invoices.blade.php

@@ -137,9 +137,9 @@
 				if (result.value) {
 					$.ajax({
 						type: "POST",
-						url: "payment/close/" + oid,
+						url: "payment/close",
 						async: false,
-						data: {_token: '{{csrf_token()}}'},
+						data: {_token: '{{csrf_token()}}', oid: oid},
 						dataType: 'json',
 						success: function (ret) {
 							if (ret.status === 'success') {

+ 3 - 3
resources/views/user/referral.blade.php

@@ -56,7 +56,7 @@
 					</div>
 					<div class="card-footer card-footer-transparent">
 						<nav class="Page navigation float-right">
-							{{$referralUserList->appends(\Illuminate\Support\Arr::except(Request::query(), 'user_page'))->links()}}
+							{{$referralUserList->appends(Arr::except(Request::query(), 'user_page'))->links()}}
 						</nav>
 					</div>
 				</div>
@@ -114,7 +114,7 @@
 							</div>
 							<div class="col-md-6 col-sm-6">
 								<nav class="Page navigation float-right">
-									{{$referralLogList->appends(\Illuminate\Support\Arr::except(Request::query(), 'user_page'))->links()}}
+									{{$referralLogList->appends(Arr::except(Request::query(), 'user_page'))->links()}}
 								</nav>
 							</div>
 						</div>
@@ -158,7 +158,7 @@
 					</div>
 					<div class="card-footer card-footer-transparent">
 						<nav class="Page navigation float-right">
-							{{$referralApplyList->appends(\Illuminate\Support\Arr::except(Request::query(), 'user_page'))->links()}}
+							{{$referralApplyList->appends(Arr::except(Request::query(), 'user_page'))->links()}}
 						</nav>
 					</div>
 				</div>

+ 20 - 5
routes/api.php

@@ -1,9 +1,24 @@
 <?php
 
-Route::group(['namespace' => 'Api'], function(){
-	// 定制客户端
-	Route::any('login', 'LoginController@login');
+// V2Ray后端WEBAPI V1版
+Route::group(['namespace' => 'Api\V2Ray', 'middleware' => ['webApi'], 'prefix' => 'v2ray/v1'], function () {
+	Route::get('node/{id}', 'V1Controller@getNodeInfo'); // 获取节点信息
+	Route::post('nodeStatus/{id}', 'V1Controller@setNodeStatus'); // 上报节点心跳信息
+	Route::post('nodeOnline/{id}', 'V1Controller@setNodeOnline'); // 上报节点在线人数
+	Route::get('userList/{id}', 'V1Controller@getUserList'); // 获取节点可用的用户列表
+	Route::post('userTraffic/{id}', 'V1Controller@setUserTraffic'); // 上报用户流量日志
+	Route::get('nodeRule/{id}', 'V1Controller@getNodeRule'); // 获取节点的审计规则
+	Route::post('trigger/{id}', 'V1Controller@addRuleLog'); // 上报用户触发的审计规则记录
+	Route::post('certificate/{id}', 'V1Controller@addCertificate'); // 上报节点伪装域名证书信息
+});
 
-	// PING检测
-	Route::get('ping', 'PingController@ping');
+// Trojan后端WEBAPI V1版
+Route::group(['namespace' => 'Api\Trojan', 'middleware' => ['webApi'], 'prefix' => 'trojan/v1'], function () {
+	Route::get('node/{id}', 'V1Controller@getNodeInfo'); // 获取节点信息
+	Route::post('nodeStatus/{id}', 'V1Controller@setNodeStatus'); // 上报节点心跳信息
+	Route::post('nodeOnline/{id}', 'V1Controller@setNodeOnline'); // 上报节点在线人数
+	Route::get('userList/{id}', 'V1Controller@getUserList'); // 获取节点可用的用户列表
+	Route::post('userTraffic/{id}', 'V1Controller@setUserTraffic'); // 上报用户流量日志
+	Route::get('nodeRule/{id}', 'V1Controller@getNodeRule'); // 获取节点的审计规则
+	Route::post('trigger/{id}', 'V1Controller@addRuleLog'); // 上报用户触发的审计规则记录
 });

+ 2 - 2
routes/channels.php

@@ -11,6 +11,6 @@
 |
 */
 
-Broadcast::channel('App.User.{id}', function($user, $id) {
-	return (int)$user->id === (int)$id;
+Broadcast::channel('App.User.{id}', function ($user, $id) {
+    return (int) $user->id === (int) $id;
 });

+ 2 - 2
routes/console.php

@@ -13,6 +13,6 @@ use Illuminate\Foundation\Inspiring;
 |
 */
 
-Artisan::command('inspire', function() {
-	$this->comment(Inspiring::quote());
+Artisan::command('inspire', function () {
+    $this->comment(Inspiring::quote());
 })->describe('Display an inspiring quote');

+ 11 - 4
routes/web.php

@@ -82,9 +82,16 @@ Route::group(['middleware' => ['isForbidden', 'isAdminLogin', 'isAdmin']], funct
 		Route::any('edit', 'NodeController@editNode'); // 编辑节点
 		Route::post('delete', 'NodeController@delNode'); // 删除节点
 		Route::get('monitor/{id}', 'NodeController@nodeMonitor'); // 节点流量监控
-		Route::post('check/{id}', 'NodeController@checkNode'); // 节点阻断检测
+		Route::post('check', 'NodeController@checkNode'); // 节点阻断检测
 		Route::post('ping', 'NodeController@pingNode'); // 节点ping测速
 		Route::get('pingLog', 'NodeController@pingLog'); //节点Ping测速日志
+		// 授权
+		Route::group(['prefix' => 'auth'], function() {
+			Route::get('/', 'NodeController@authList'); // 节点授权列表
+			Route::post('add', 'NodeController@addAuth'); // 添加节点授权
+			Route::post('delete', 'NodeController@delAuth'); // 删除节点授权
+			Route::post('refresh', 'NodeController@refreshAuth'); // 重置节点授权
+		});
 	});
 
 	Route::group(['namespace' => 'Admin'], function() {
@@ -142,12 +149,12 @@ Route::group(['middleware' => ['isForbidden', 'isAdminLogin', 'isAdmin']], funct
 			Route::get('/', 'RuleController@ruleList'); // 审计规则列表
 			Route::post('add', 'RuleController@addRule'); // 添加审计规则
 			Route::post('edit', 'RuleController@editRule'); // 删除审计规则
-			Route::post('delete/{id}', 'RuleController@delRule'); // 删除审计规则
+			Route::post('delete', 'RuleController@delRule'); // 删除审计规则
 			Route::group(['prefix' => 'group'], function() {
 				Route::get('/', 'RuleController@ruleGroupList'); // 审计规则分组列表
 				Route::any('add', 'RuleController@addRuleGroup'); // 添加审计规则分组
 				Route::any('edit', 'RuleController@editRuleGroup'); // 编辑审计规则分组
-				Route::post('delete/{id}', 'RuleController@delRuleGroup'); // 删除审计规则分组
+				Route::post('delete', 'RuleController@delRuleGroup'); // 删除审计规则分组
 				Route::any('assign', 'RuleController@assignNode'); // 规则分组关联节点
 			});
 			Route::get('log', 'RuleController@ruleLogList'); // 用户触发审计规则日志
@@ -190,7 +197,7 @@ Route::group(['middleware' => ['isForbidden', 'isMaintenance', 'isLogin']], func
 
 	Route::group(['prefix' => 'payment'], function() {
 		Route::post('purchase', 'PaymentController@purchase'); // 创建支付
-		Route::post('close/{id}', 'PaymentController@close'); // 关闭支付单
+		Route::post('close', 'PaymentController@close'); // 关闭支付单
 		Route::get('getStatus', 'PaymentController@getStatus'); // 获取支付单状态
 		Route::get('{trade_no}', 'PaymentController@detail'); // 支付单详情
 	});

+ 76 - 46
sql/db.sql

@@ -25,49 +25,48 @@
 -- ----------------------------
 CREATE TABLE `ss_node`
 (
-    `id`                      INT(10) UNSIGNED     NOT NULL AUTO_INCREMENT,
-    `type`                    TINYINT(1) UNSIGNED  NOT NULL DEFAULT '1' COMMENT '服务类型:1-ShadowsocksR、2-V2ray',
-    `name`                    VARCHAR(128)         NOT NULL DEFAULT '' COMMENT '名称',
-    `country_code`            CHAR(5)              NOT NULL DEFAULT 'un' COMMENT '国家代码',
-    `server`                  VARCHAR(255)         NULL     DEFAULT NULL COMMENT '服务器域名地址',
-    `ip`                      CHAR(15)             NULL     DEFAULT NULL COMMENT '服务器IPV4地址',
-    `ipv6`                    VARCHAR(128)         NULL     DEFAULT NULL COMMENT '服务器IPV6地址',
-    `relay_server`            VARCHAR(255)         NULL     DEFAULT NULL COMMENT '中转地址',
-    `relay_port`              SMALLINT(5) UNSIGNED NULL     DEFAULT 0 COMMENT '中转端口',
-    `level`                   TINYINT(3) UNSIGNED  NOT NULL DEFAULT '0' COMMENT '等级:0-无等级,全部可见',
-    `speed_limit`             BIGINT(20) UNSIGNED  NOT NULL DEFAULT '0' COMMENT '节点限速,为0表示不限速,单位Byte',
-    `client_limit`            TINYINT(3) UNSIGNED  NOT NULL DEFAULT 0 COMMENT '设备数限制',
-    `description`             VARCHAR(255)         NULL     DEFAULT NULL COMMENT '节点简单描述',
-    `method`                  VARCHAR(32)          NOT NULL DEFAULT 'aes-256-cfb' COMMENT '加密方式',
-    `protocol`                VARCHAR(64)          NOT NULL DEFAULT 'origin' COMMENT '协议',
-    `protocol_param`          VARCHAR(128)         NULL     DEFAULT NULL COMMENT '协议参数',
-    `obfs`                    VARCHAR(64)          NOT NULL DEFAULT 'plain' COMMENT '混淆',
-    `obfs_param`              VARCHAR(255)         NULL     DEFAULT NULL COMMENT '混淆参数',
-    `traffic_rate`            FLOAT(6, 2) UNSIGNED NOT NULL DEFAULT '1.00' COMMENT '流量比率',
-    `is_subscribe`            BIT                  NOT NULL DEFAULT 1 COMMENT '是否允许用户订阅该节点:0-否、1-是',
-    `is_ddns`                 BIT                  NOT NULL DEFAULT 0 COMMENT '是否使用DDNS:0-否、1-是',
-    `is_relay`                BIT                  NOT NULL DEFAULT 0 COMMENT '是否中转节点:0-否、1-是',
-    `is_udp`                  BIT                  NOT NULL DEFAULT 1 COMMENT '是否启用UDP:0-不启用、1-启用',
-    `ssh_port`                SMALLINT(5) UNSIGNED NOT NULL DEFAULT '22' COMMENT 'SSH端口',
-    `detection_type`          TINYINT(1)           NOT NULL DEFAULT '1' COMMENT '节点检测: 0-关闭、1-只检测TCP、2-只检测ICMP、3-检测全部',
-    `compatible`              BIT                  NOT NULL DEFAULT 0 COMMENT '兼容SS',
-    `single`                  BIT                  NOT NULL DEFAULT 0 COMMENT '启用单端口功能:0-否、1-是',
-    `port`                    SMALLINT(5) UNSIGNED NULL     DEFAULT NULL COMMENT '单端口的端口号或连接端口号',
-    `passwd`                  VARCHAR(255)         NULL     DEFAULT NULL COMMENT '单端口的连接密码',
-    `sort`                    TINYINT(3) UNSIGNED  NOT NULL DEFAULT '0' COMMENT '排序值,值越大越靠前显示',
-    `status`                  BIT                  NOT NULL DEFAULT 1 COMMENT '状态:0-维护、1-正常',
-    `v2_alter_id`             SMALLINT(5) UNSIGNED NOT NULL DEFAULT '16' COMMENT 'V2Ray额外ID',
-    `v2_port`                 SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'V2Ray服务端口',
-    `v2_method`               VARCHAR(32)          NOT NULL DEFAULT 'aes-128-gcm' COMMENT 'V2Ray加密方式',
-    `v2_net`                  VARCHAR(16)          NOT NULL DEFAULT 'tcp' COMMENT 'V2Ray传输协议',
-    `v2_type`                 VARCHAR(32)          NOT NULL DEFAULT 'none' COMMENT 'V2Ray伪装类型',
-    `v2_host`                 VARCHAR(255)         NOT NULL DEFAULT '' COMMENT 'V2Ray伪装的域名',
-    `v2_path`                 VARCHAR(255)         NOT NULL DEFAULT '' COMMENT 'V2Ray的WS/H2路径',
-    `v2_tls`                  BIT                  NOT NULL DEFAULT 0 COMMENT 'V2Ray后端TLS:0-未开启、1-开启',
-    `v2_tls_insecure`         BIT                  NOT NULL DEFAULT 0 COMMENT '是否允许不安全连接',
-    `v2_tls_insecure_ciphers` BIT                  NOT NULL DEFAULT 0 COMMENT '是否允许不安全的加密方式',
-    `created_at`              DATETIME             NOT NULL,
-    `updated_at`              DATETIME             NOT NULL,
+    `id`             INT(10) UNSIGNED     NOT NULL AUTO_INCREMENT,
+    `type`           TINYINT(1) UNSIGNED  NOT NULL DEFAULT '1' COMMENT '服务类型:1-ShadowsocksR、2-V2ray',
+    `name`           VARCHAR(128)         NOT NULL DEFAULT '' COMMENT '名称',
+    `country_code`   CHAR(5)              NOT NULL DEFAULT 'un' COMMENT '国家代码',
+    `server`         VARCHAR(255)         NULL     DEFAULT NULL COMMENT '服务器域名地址',
+    `ip`             CHAR(15)             NULL     DEFAULT NULL COMMENT '服务器IPV4地址',
+    `ipv6`           VARCHAR(128)         NULL     DEFAULT NULL COMMENT '服务器IPV6地址',
+    `relay_server`   VARCHAR(255)         NULL     DEFAULT NULL COMMENT '中转地址',
+    `relay_port`     SMALLINT(5) UNSIGNED NULL     DEFAULT 0 COMMENT '中转端口',
+    `level`          TINYINT(3) UNSIGNED  NOT NULL DEFAULT '0' COMMENT '等级:0-无等级,全部可见',
+    `speed_limit`    BIGINT(20) UNSIGNED  NOT NULL DEFAULT '0' COMMENT '节点限速,为0表示不限速,单位Byte',
+    `client_limit`   TINYINT(3) UNSIGNED  NOT NULL DEFAULT 0 COMMENT '设备数限制',
+    `description`    VARCHAR(255)         NULL     DEFAULT NULL COMMENT '节点简单描述',
+    `method`         VARCHAR(32)          NOT NULL DEFAULT 'aes-256-cfb' COMMENT '加密方式',
+    `protocol`       VARCHAR(64)          NOT NULL DEFAULT 'origin' COMMENT '协议',
+    `protocol_param` VARCHAR(128)         NULL     DEFAULT NULL COMMENT '协议参数',
+    `obfs`           VARCHAR(64)          NOT NULL DEFAULT 'plain' COMMENT '混淆',
+    `obfs_param`     VARCHAR(255)         NULL     DEFAULT NULL COMMENT '混淆参数',
+    `traffic_rate`   FLOAT(6, 2) UNSIGNED NOT NULL DEFAULT '1.00' COMMENT '流量比率',
+    `is_subscribe`   BIT                  NOT NULL DEFAULT 1 COMMENT '是否允许用户订阅该节点:0-否、1-是',
+    `is_ddns`        BIT                  NOT NULL DEFAULT 0 COMMENT '是否使用DDNS:0-否、1-是',
+    `is_relay`       BIT                  NOT NULL DEFAULT 0 COMMENT '是否中转节点:0-否、1-是',
+    `is_udp`         BIT                  NOT NULL DEFAULT 1 COMMENT '是否启用UDP:0-不启用、1-启用',
+    `push_port`      SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' COMMENT '消息推送端口',
+    `detection_type` TINYINT(1)           NOT NULL DEFAULT '1' COMMENT '节点检测: 0-关闭、1-只检测TCP、2-只检测ICMP、3-检测全部',
+    `compatible`     BIT                  NOT NULL DEFAULT 0 COMMENT '兼容SS',
+    `single`         BIT                  NOT NULL DEFAULT 0 COMMENT '启用单端口功能:0-否、1-是',
+    `port`           SMALLINT(5) UNSIGNED NULL     DEFAULT NULL COMMENT '单端口的端口号或连接端口号',
+    `passwd`         VARCHAR(255)         NULL     DEFAULT NULL COMMENT '单端口的连接密码',
+    `sort`           TINYINT(3) UNSIGNED  NOT NULL DEFAULT '0' COMMENT '排序值,值越大越靠前显示',
+    `status`         BIT                  NOT NULL DEFAULT 1 COMMENT '状态:0-维护、1-正常',
+    `v2_alter_id`    SMALLINT(5) UNSIGNED NOT NULL DEFAULT '16' COMMENT 'V2Ray额外ID',
+    `v2_port`        SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'V2Ray服务端口',
+    `v2_method`      VARCHAR(32)          NOT NULL DEFAULT 'aes-128-gcm' COMMENT 'V2Ray加密方式',
+    `v2_net`         VARCHAR(16)          NOT NULL DEFAULT 'tcp' COMMENT 'V2Ray传输协议',
+    `v2_type`        VARCHAR(32)          NOT NULL DEFAULT 'none' COMMENT 'V2Ray伪装类型',
+    `v2_host`        VARCHAR(255)         NOT NULL DEFAULT '' COMMENT 'V2Ray伪装的域名',
+    `v2_path`        VARCHAR(255)         NOT NULL DEFAULT '' COMMENT 'V2Ray的WS/H2路径',
+    `v2_tls`         BIT                  NOT NULL DEFAULT 0 COMMENT 'V2Ray后端TLS:0-未开启、1-开启',
+    `tls_provider`   TEXT                 NULL     DEFAULT NULL COMMENT 'V2Ray节点的TLS提供商授权信息',
+    `created_at`     DATETIME             NOT NULL,
+    `updated_at`     DATETIME             NOT NULL,
     PRIMARY KEY (`id`),
     INDEX `idx_sub` (`is_subscribe`)
 ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT ='节点信息表';
@@ -355,9 +354,9 @@ VALUES ('1', 'is_rand_port', 0),
        ('48', 'subscribe_domain', ''),
        ('49', 'auto_release_port', 1),
        ('50', 'website_callback_url', ''),
-       ('51', 'youzan_client_id', ''),
-       ('52', 'youzan_client_secret', ''),
-       ('53', 'kdt_id', ''),
+       ('51', 'vnet_license', ''),
+       ('52', 'v2ray_license', ''),
+       ('53', 'trojan_license', ''),
        ('54', 'initial_labels_for_user', ''),
        ('55', 'website_analytics', ''),
        ('56', 'website_customer_service', ''),
@@ -1370,6 +1369,37 @@ CREATE TABLE `node_rule`
 ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT ='节点审计规则关联';
 
 
+-- ----------------------------
+-- Table structure for `node_auth`
+-- ----------------------------
+CREATE TABLE `node_auth`
+(
+    `id`         INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+    `node_id`    INT(10) UNSIGNED NOT NULL                          DEFAULT '0' COMMENT '授权节点ID',
+    `key`        CHAR(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT '' COMMENT '认证KEY',
+    `secret`     CHAR(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin  DEFAULT '' COMMENT '通信密钥',
+    `created_at` DATETIME         NULL                              DEFAULT NULL COMMENT '创建时间',
+    `updated_at` DATETIME         NULL                              DEFAULT NULL COMMENT '最后更新时间',
+    PRIMARY KEY (`id`),
+    INDEX `id` (`id`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT ='节点授权密钥表';
+
+
+-- ----------------------------
+-- Table structure for `node_certificate`
+-- ----------------------------
+CREATE TABLE `node_certificate`
+(
+    `id`         INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+    `domain`     VARCHAR(255)     NOT NULL COMMENT '域名',
+    `key`        TEXT             NULL COMMENT '域名证书KEY',
+    `pem`        TEXT             NULL COMMENT '域名证书PEM',
+    `created_at` DATETIME         NOT NULL,
+    `updated_at` DATETIME         NOT NULL,
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COLLATE = 'utf8mb4_unicode_ci' COMMENT ='域名证书';
+
+
 -- ----------------------------
 -- Table structure for failed_jobs
 -- ----------------------------

+ 32 - 0
sql/mod/20200630.sql

@@ -0,0 +1,32 @@
+ALTER TABLE `ss_node`
+    CHANGE `ssh_port` `push_port` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0' COMMENT '消息推送端口',
+    ADD `tls_provider`            TEXT                 NULL     DEFAULT NULL COMMENT 'V2Ray节点的TLS提供商授权信息' AFTER `v2_tls`,
+    DROP `v2_tls_insecure`,
+    DROP `v2_tls_insecure_ciphers`;
+
+CREATE TABLE `node_auth`
+(
+    `id`         INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+    `node_id`    INT(10) UNSIGNED NOT NULL                          DEFAULT '0' COMMENT '授权节点ID',
+    `key`        CHAR(16) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin DEFAULT '' COMMENT '认证KEY',
+    `secret`     CHAR(8) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin  DEFAULT '' COMMENT '通信密钥',
+    `created_at` DATETIME         NULL                              DEFAULT NULL COMMENT '创建时间',
+    `updated_at` DATETIME         NULL                              DEFAULT NULL COMMENT '最后更新时间',
+    PRIMARY KEY (`id`),
+    INDEX `id` (`id`)
+) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT ='节点授权密钥表';
+
+CREATE TABLE `node_certificate`
+(
+    `id`         INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
+    `domain`     VARCHAR(255)     NOT NULL COMMENT '域名',
+    `key`        TEXT             NULL COMMENT '域名证书KEY',
+    `pem`        TEXT             NULL COMMENT '域名证书PEM',
+    `created_at` DATETIME         NOT NULL,
+    `updated_at` DATETIME         NOT NULL,
+    PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB COLLATE = 'utf8mb4_unicode_ci' COMMENT ='域名证书';
+
+UPDATE `config` SET `name` = 'vnet_license' WHERE `config`.`id` = 51;
+UPDATE `config` SET `name` = 'v2ray_license' WHERE `config`.`id` = 52;
+UPDATE `config` SET `name` = 'trojan_license' WHERE `config`.`id` = 53;

+ 3 - 3
webpack.mix.js

@@ -1,4 +1,4 @@
-let mix = require('laravel-mix');
+const mix = require('laravel-mix');
 
 /*
  |--------------------------------------------------------------------------
@@ -11,5 +11,5 @@ let mix = require('laravel-mix');
  |
  */
 
-mix.js('resources/assets/js/app.js', 'public/js')
-   .sass('resources/assets/sass/app.scss', 'public/css');
+mix.js('resources/js/app.js', 'public/js')
+    .sass('resources/sass/app.scss', 'public/css');