ソースを参照

独立节点阻断检测,支付依赖升级

兔姬桑 5 年 前
コミット
bc205b171f

+ 61 - 0
app/Components/NetworkDetection.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace App\Components;
+
+use Exception;
+use Log;
+
+class NetworkDetection
+{
+	/**
+	 * 用api.50network.com进行节点阻断检测
+	 *
+	 * @param string  $ip   被检测的IP
+	 * @param boolean $type TRUE 为ICMP,FALSE 为tcp
+	 * @param int     $port 检测端口,默认为空
+	 *
+	 * @return bool|string
+	 */
+	public static function networkCheck($ip, $type, $port = NULL)
+	{
+		$url = 'https://api.50network.com/china-firewall/check/ip/'.($type? 'icmp/' : ($port? 'tcp_port/' : 'tcp_ack/')).$ip.($port? '/'.$port : '');
+		$checkName = $type? 'ICMP' : 'TCP';
+
+		try{
+			$ret = json_decode(Curl::send($url), TRUE);
+			if(!$ret){
+				Log::warning("【".$checkName."阻断检测】检测".$ip."时,接口返回异常访问链接:".$url);
+
+				return FALSE;
+			}elseif(!$ret['success']){
+				if($ret['error'] == "execute timeout (3s)"){
+					sleep(10);
+
+					return self::networkCheck($ip, $type, $port);
+				}else{
+					Log::warning("【".$checkName."阻断检测】检测".$ip.($port? : '')."时,返回".json_encode($ret));
+
+				}
+
+
+				return FALSE;
+			}
+		} catch(Exception $e){
+			Log::warning("【".$checkName."阻断检测】检测".$ip."时,接口请求超时".$e);
+
+			return FALSE;
+		}
+
+		if($ret['firewall-enable'] && $ret['firewall-disable']){
+			return "通讯正常"; // 正常
+		}elseif($ret['firewall-enable'] && !$ret['firewall-disable']){
+			return "海外阻断"; // 国外访问异常
+		}elseif(!$ret['firewall-enable'] && $ret['firewall-disable']){
+			return "国内阻断"; // 被墙
+		}else{
+			return "机器宕机"; // 服务器宕机
+		}
+	}
+}
+
+?>

+ 3 - 55
app/Console/Commands/NodeBlockedDetection.php

@@ -2,13 +2,12 @@
 
 namespace App\Console\Commands;
 
-use App\Components\Curl;
 use App\Components\Helpers;
+use App\Components\NetworkDetection;
 use App\Components\ServerChan;
 use App\Http\Models\SsNode;
 use App\Mail\nodeCrashWarning;
 use Cache;
-use Exception;
 use Illuminate\Console\Command;
 use Log;
 use Mail;
@@ -61,16 +60,15 @@ class NodeBlockedDetection extends Command
 				}
 			}
 			if($node->detectionType != 1){
-				$icmpCheck = $this->networkCheck($node->ip, TRUE, FALSE);
+				$icmpCheck = NetworkDetection::networkCheck($node->ip, TRUE);
 				if($icmpCheck != FALSE && $icmpCheck != "通讯正常"){
 					$message .= "| ".$node->name." | ICMP | ".$icmpCheck." |\r\n";
 					$sendText = TRUE;
 					$info = TRUE;
 				}
 			}
-
 			if($node->detectionType != 2){
-				$tcpCheck = $this->networkCheck($node->ip, FALSE, $node->single? $node->port : FALSE);
+				$tcpCheck = NetworkDetection::networkCheck($node->ip, FALSE, $node->single? $node->port : NULL);
 				if($tcpCheck != FALSE && $tcpCheck != "通讯正常"){
 					$message .= "| ".$node->name." | TCP | ".$tcpCheck." |\r\n";
 					$sendText = TRUE;
@@ -124,54 +122,4 @@ class NodeBlockedDetection extends Command
 		}
 		ServerChan::send($title, $content);
 	}
-
-	/**
-	 * 用api.50network.com进行节点阻断检测
-	 *
-	 * @param string  $ip   被检测的IP
-	 * @param boolean $type true 为ICMP,false 为tcp
-	 * @param int     $port 检测端口
-	 *
-	 * @return bool|string
-	 */
-	private function networkCheck($ip, $type, $port)
-	{
-		$url = 'https://api.50network.com/china-firewall/check/ip/'.($type? 'icmp/' : ($port? 'tcp_port/' : 'tcp_ack/')).$ip.($port? '/'.$port : '');
-		$checkName = $type? 'ICMP' : 'TCP';
-
-		try{
-			$ret = json_decode(Curl::send($url), TRUE);
-			if(!$ret){
-				Log::warning("【".$checkName."阻断检测】检测".$ip."时,接口返回异常访问链接:".$url);
-
-				return FALSE;
-			}elseif(!$ret['success']){
-				if($ret['error'] == "execute timeout (3s)"){
-					sleep(10);
-
-					return $this->networkCheck($ip, $type, $port);
-				}else{
-					Log::warning("【".$checkName."阻断检测】检测".$ip.($port? : '')."时,返回".json_encode($ret));
-
-				}
-
-
-				return FALSE;
-			}
-		} catch(Exception $e){
-			Log::warning("【".$checkName."阻断检测】检测".$ip."时,接口请求超时".$e);
-
-			return FALSE;
-		}
-
-		if($ret['firewall-enable'] && $ret['firewall-disable']){
-			return "通讯正常"; // 正常
-		}elseif($ret['firewall-enable'] && !$ret['firewall-disable']){
-			return "海外阻断"; // 国外访问异常
-		}elseif(!$ret['firewall-enable'] && $ret['firewall-disable']){
-			return "国内阻断"; // 被墙
-		}else{
-			return "机器宕机"; // 服务器宕机
-		}
-	}
 }

+ 39 - 20
app/Http/Controllers/AdminController.php

@@ -4,6 +4,7 @@ namespace App\Http\Controllers;
 
 use App\Components\Helpers;
 use App\Components\IPIP;
+use App\Components\NetworkDetection;
 use App\Components\QQWry;
 use App\Http\Models\Article;
 use App\Http\Models\Config;
@@ -522,32 +523,50 @@ class AdminController extends Controller
 	// 节点列表
 	public function nodeList(Request $request)
 	{
-		$status = $request->input('status');
+		if($request->isMethod('POST')){
+			$id = $request->input('id');
+			$node = SsNode::query()->whereKey($id)->first();
+			// 使用DDNS的node先通过gethostbyname获取ipv4地址
+			if($node->is_ddns){
+				$ip = gethostbyname($node->server);
+				if(strcmp($ip, $node->server) != 0){
+					$node->ip = $ip;
+				}else{
+					return Response::json(['status' => 'fail', 'title' => 'IP获取错误', 'message' => $node->name.'IP获取失败']);
+				}
+			}
+			$data[0] = NetworkDetection::networkCheck($node->ip,TRUE); //ICMP
+			$data[1] = NetworkDetection::networkCheck($node->ip, FALSE, $node->single? $node->port : NULL); //TCP
+
+			return Response::json(['status' => 'success', 'title' => '['.$node->name.']阻断信息', 'message'=>$data]);
+		}else{
+			$status = $request->input('status');
 
-		$query = SsNode::query();
+			$query = SsNode::query();
 
-		if(isset($status)){
-			$query->where('status', $status);
-		}
+			if(isset($status)){
+				$query->where('status', $status);
+			}
 
-		$nodeList = $query->orderBy('status', 'desc')->orderBy('id', 'asc')->paginate(15)->appends($request->except('page'));
-		foreach($nodeList as $node){
-			// 在线人数
-			$online_log = SsNodeOnlineLog::query()->where('node_id', $node->id)->where('log_time', '>=', strtotime("-5 minutes"))->orderBy('id', 'desc')->first();
-			$node->online_users = empty($online_log)? 0 : $online_log->online_user;
+			$nodeList = $query->orderBy('status', 'desc')->orderBy('id', 'asc')->paginate(15)->appends($request->except('page'));
+			foreach($nodeList as $node){
+				// 在线人数
+				$online_log = SsNodeOnlineLog::query()->where('node_id', $node->id)->where('log_time', '>=', strtotime("-5 minutes"))->orderBy('id', 'desc')->first();
+				$node->online_users = empty($online_log)? 0 : $online_log->online_user;
 
-			// 已产生流量
-			$totalTraffic = SsNodeTrafficDaily::query()->where('node_id', $node->id)->sum('total');
-			$node->transfer = flowAutoShow($totalTraffic);
+				// 已产生流量
+				$totalTraffic = SsNodeTrafficDaily::query()->where('node_id', $node->id)->sum('total');
+				$node->transfer = flowAutoShow($totalTraffic);
 
-			// 负载(10分钟以内)
-			$node_info = SsNodeInfo::query()->where('node_id', $node->id)->where('log_time', '>=', strtotime("-10 minutes"))->orderBy('id', 'desc')->first();
-			$node->isOnline = empty($node_info) || empty($node_info->load)? 0 : 1;
-			$node->load = $node->isOnline? $node_info->load : '离线';
-			$node->uptime = empty($node_info)? 0 : seconds2time($node_info->uptime);
-		}
+				// 负载(10分钟以内)
+				$node_info = SsNodeInfo::query()->where('node_id', $node->id)->where('log_time', '>=', strtotime("-10 minutes"))->orderBy('id', 'desc')->first();
+				$node->isOnline = empty($node_info) || empty($node_info->load)? 0 : 1;
+				$node->load = $node->isOnline? $node_info->load : '离线';
+				$node->uptime = empty($node_info)? 0 : seconds2time($node_info->uptime);
+			}
 
-		$view['nodeList'] = $nodeList;
+			$view['nodeList'] = $nodeList;
+		}
 
 		return Response::view('admin.nodeList', $view);
 	}

+ 1 - 1
app/Http/Controllers/Api/AlipayController.php

@@ -24,10 +24,10 @@ class AlipayController extends Controller
 	{
 		Log::info("【支付宝国际】回调接口[POST]:".var_export($request->all(), TRUE));
 
-		$result = "fail";
 		$alipayNotify = new AlipayNotify(self::$systemConfig['alipay_sign_type'], self::$systemConfig['alipay_partner'], self::$systemConfig['alipay_key'], self::$systemConfig['alipay_private_key'], self::$systemConfig['alipay_public_key'], self::$systemConfig['alipay_transport']);
 
 		// 验证支付宝交易
+		$result = "fail";
 		$verify_result = $alipayNotify->verifyNotify();
 		if($verify_result){ // 验证成功
 			$result = "success";

+ 35 - 22
app/Http/Controllers/Api/F2fpayController.php

@@ -4,10 +4,13 @@ namespace App\Http\Controllers\Api;
 
 use App\Components\Callback;
 use App\Http\Controllers\Controller;
+use Exception;
 use Illuminate\Http\Request;
+use InvalidArgumentException;
 use Log;
-use Payment\Client\Query;
-use Payment\Common\PayException;
+use Payment\Client;
+use Payment\Exceptions\ClassNotFoundException;
+use Payment\Exceptions\GatewayException;
 
 class F2fpayController extends Controller
 {
@@ -24,32 +27,42 @@ class F2fpayController extends Controller
 	public function store(Request $request)
 	{
 		Log::info("【支付宝当面付】回调接口[POST]:".var_export($request->all(), TRUE));
+		$aliConfig = [
+			'use_sandbox'     => FALSE,
+			'app_id'          => self::$systemConfig['f2fpay_app_id'],
+			'sign_type'       => 'RSA2',
+			'ali_public_key'  => self::$systemConfig['f2fpay_public_key'],
+			'rsa_private_key' => self::$systemConfig['f2fpay_private_key'],
+			'notify_url'      => self::$systemConfig['website_url']."/api/f2fpay", // 异步回调接口
+			'return_url'      => self::$systemConfig['website_url'],
+		];
 
-		$result = "fail";
+		$data = [
+			'trade_no'       => $request->input('out_trade_no'),
+			'transaction_id' => $request->input('trade_no'),
+		];
 
+		// 使用
 		try{
-			$verify_result = Query::run('ali_charge', [
-				'use_sandbox'     => FALSE,
-				"partner"         => self::$systemConfig['f2fpay_app_id'],
-				'app_id'          => self::$systemConfig['f2fpay_app_id'],
-				'sign_type'       => 'RSA2',
-				'ali_public_key'  => self::$systemConfig['f2fpay_public_key'],
-				'rsa_private_key' => self::$systemConfig['f2fpay_private_key'],
-				'notify_url'      => self::$systemConfig['website_url']."/api/f2fpay", // 异步回调接口
-				'return_url'      => self::$systemConfig['website_url'],
-				'return_raw'      => FALSE
-			], [
-				'out_trade_no' => $request->input('out_trade_no'),
-				'trade_no'     => $request->input('trade_no'),
-			]);
-
+			$client = new Client(Client::ALIPAY, $aliConfig);
+			$verify_result = $client->tradeQuery($data);
 			Log::info("【支付宝当面付】回调验证查询:".var_export($verify_result, TRUE));
-		} catch(PayException $e){
-			Log::info("【支付宝当面付】回调验证查询出错:".var_export($e->errorMessage(), TRUE));
-			exit($result);
+		} catch(InvalidArgumentException $e){
+			Log::error("【支付宝当面付】回调信息错误: ".$e->getMessage());
+			exit;
+		} catch(GatewayException $e){
+			Log::error("【支付宝当面付】建立支付错误: ".$e->getMessage());
+			exit;
+		} catch(ClassNotFoundException $e){
+			Log::error("【支付宝当面付】未知类型: ".$e->getMessage());
+			exit;
+		} catch(Exception $e){
+			Log::error("【支付宝当面付】错误: ".$e->getMessage());
+			exit;
 		}
 
-		if($verify_result['is_success'] == 'T'){ // 验证成功
+		$result = "fail";
+		if($verify_result['code'] == 10000 && $verify_result['msg'] == "Success"){ // 验证成功
 			$result = "success";
 			if($_POST['trade_status'] == 'TRADE_FINISHED' || $_POST['trade_status'] == 'TRADE_SUCCESS'){
 				// 商户订单号

+ 34 - 1
app/Http/Controllers/CouponController.php

@@ -51,7 +51,40 @@ class CouponController extends Controller
 	public function addCoupon(Request $request)
 	{
 		if($request->isMethod('POST')){
-			$this->validate($request, ['name' => 'required', 'type' => 'required|integer|between:1,3', 'usage' => 'required|integer|between:1,2', 'num' => 'required|integer|min:1', 'amount' => 'required_unless:type,2|numeric|min:0.01|nullable', 'discount' => 'required_if:type,2|numeric|between:1,9.9|nullable', 'available_start' => 'required|date|before_or_equal:available_end', 'available_end' => 'required|date|after_or_equal:available_start',], ['name.required' => '请填入卡券名称', 'type.required' => '请选择卡券类型', 'type.integer' => '卡券类型不合法,请重选', 'type.between' => '卡券类型不合法,请重选', 'usage.required' => '请选择卡券用途', 'usage.integer' => '卡券用途不合法,请重选', 'usage.between' => '卡券用途不合法,请重选', 'num.required' => '请填写卡券数量', 'num.integer' => '卡券数量不合法', 'num.min' => '卡券数量不合法,最小1', 'amount.required_unless' => '请填入卡券面值', 'amount.numeric' => '卡券金额不合法', 'amount.min' => '卡券金额不合法,最小0.01', 'discount.required_if' => '请填入卡券折扣', 'discount.numeric' => '卡券折扣不合法', 'discount.between' => '卡券折扣不合法,有效范围:1 ~ 9.9', 'available_start.required' => '请填入有效期', 'available_start.date' => '有效期不合法', 'available_start.before_or_equal' => '有效期不合法', 'available_end.required' => '请填入有效期', 'available_end.date' => '有效期不合法', 'available_end.after_or_equal' => '有效期不合法']);
+			$this->validate($request, [
+				'name'            => 'required',
+				'sn'              => 'mail|unique:coupon',
+				'type'            => 'required|integer|between:1,3',
+				'usage'           => 'required|integer|between:1,2',
+				'num'             => 'required|integer|min:1',
+				'amount'          => 'required_unless:type,2|numeric|min:0.01|nullable',
+				'discount'        => 'required_if:type,2|numeric|between:1,9.9|nullable',
+				'available_start' => 'required|date|before_or_equal:available_end',
+				'available_end'   => 'required|date|after_or_equal:available_start',
+			], [
+				'name.required'                   => '请填入卡券名称',
+				'type.required'                   => '请选择卡券类型',
+				'type.integer'                    => '卡券类型不合法,请重选',
+				'type.between'                    => '卡券类型不合法,请重选',
+				'usage.required'                  => '请选择卡券用途',
+				'usage.integer'                   => '卡券用途不合法,请重选',
+				'usage.between'                   => '卡券用途不合法,请重选',
+				'num.required'                    => '请填写卡券数量',
+				'num.integer'                     => '卡券数量不合法',
+				'num.min'                         => '卡券数量不合法,最小1',
+				'amount.required_unless'          => '请填入卡券面值',
+				'amount.numeric'                  => '卡券金额不合法',
+				'amount.min'                      => '卡券金额不合法,最小0.01',
+				'discount.required_if'            => '请填入卡券折扣',
+				'discount.numeric'                => '卡券折扣不合法',
+				'discount.between'                => '卡券折扣不合法,有效范围:1 ~ 9.9',
+				'available_start.required'        => '请填入有效期',
+				'available_start.date'            => '有效期不合法',
+				'available_start.before_or_equal' => '有效期不合法',
+				'available_end.required'          => '请填入有效期',
+				'available_end.date'              => '有效期不合法',
+				'available_end.after_or_equal'    => '有效期不合法'
+			]);
 
 			$type = $request->input('type');
 

+ 49 - 17
app/Http/Controllers/PaymentController.php

@@ -15,8 +15,11 @@ use Auth;
 use DB;
 use Exception;
 use Illuminate\Http\Request;
+use InvalidArgumentException;
 use Log;
-use Payment\Client\Charge;
+use Payment\Client;
+use Payment\Exceptions\ClassNotFoundException;
+use Payment\Exceptions\GatewayException;
 use Response;
 use Validator;
 
@@ -31,7 +34,7 @@ class PaymentController extends Controller
 {
 	use Callback;
 
-// 创建支付订单
+	// 创建支付订单
 	public function create(Request $request)
 	{
 		$goods_id = $request->input('goods_id');
@@ -151,23 +154,52 @@ class PaymentController extends Controller
 					$pay_way = 2;
 					// TODO:goods表里增加一个字段用于自定义商品付款时展示的商品名称,
 					// TODO:这里增加一个随机商品列表,根据goods的价格随机取值
-					$result = Charge::run("ali_qr", [
-						'use_sandbox'     => FALSE,
-						"partner"         => self::$systemConfig['f2fpay_app_id'],
+
+					$aliConfig = [
+						'use_sandbox'     => FALSE, // 是否使用沙盒模式
 						'app_id'          => self::$systemConfig['f2fpay_app_id'],
-						'sign_type'       => 'RSA2',
+						'sign_type'       => 'RSA2', // RSA  RSA2
 						'ali_public_key'  => self::$systemConfig['f2fpay_public_key'],
 						'rsa_private_key' => self::$systemConfig['f2fpay_private_key'],
-						'notify_url'      => self::$systemConfig['website_url']."/api/f2fpay", // 异步回调接口
+						'limit_pay'       => [
+							//'balance',// 余额
+							//'moneyFund',// 余额宝
+							//'debitCardExpress',// 	借记卡快捷
+							//'creditCard',//信用卡
+							//'creditCardExpress',// 信用卡快捷
+							//'creditCardCartoon',//信用卡卡通
+							//'credit_group',// 信用支付类型(包含信用卡卡通、信用卡快捷、花呗、花呗分期)
+						], // 用户不可用指定渠道支付当有多个渠道时用“,”分隔
+						'notify_url'      => self::$systemConfig['website_url']."/api/f2fpay",
 						'return_url'      => self::$systemConfig['website_url'],
-						'return_raw'      => FALSE
-					],
-						[
-							'body'     => '',
-							'subject'  => self::$systemConfig['f2fpay_subject_name'],
-							'order_no' => $orderSn,
-							'amount'   => $amount,
-						]);
+						'fee_type'        => 'CNY', // 货币类型  当前仅支持该字段
+					];
+
+					$payData = [
+						'body'        => '',
+						'subject'     => self::$systemConfig['f2fpay_subject_name']? : self::$systemConfig['website_name'],
+						'trade_no'    => $orderSn,
+						'time_expire' => time()+9000, // 表示必须 1000s 内付款
+						'amount'      => $amount, // 单位为元 ,最小为0.01
+					];
+
+					try{
+						$client = new Client(Client::ALIPAY, $aliConfig);
+						$result = $client->pay(Client::ALI_CHANNEL_QR, $payData);
+					} catch(InvalidArgumentException $e){
+						Log::error("【支付宝当面付】输入信息错误: ".$e->getMessage());
+						exit;
+					} catch(GatewayException $e){
+						Log::error("【支付宝当面付】建立支付错误: ".$e->getMessage()." | ".var_dump($e->getRaw()));
+						exit;
+					} catch(ClassNotFoundException $e){
+						Log::error("【支付宝当面付】未知类型: ".$e->getMessage());
+						exit;
+					} catch(Exception $e){
+						Log::error("【支付宝当面付】错误: ".$e->getMessage());
+						exit;
+					}
+
 				}else{
 					return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:未知支付类型']);
 				}
@@ -182,8 +214,8 @@ class PaymentController extends Controller
 				if(self::$systemConfig['is_alipay'] && $pay_type == 4){
 					$payment->qr_code = $result;
 				}elseif(self::$systemConfig['is_f2fpay'] && $pay_type == 5){
-					$payment->qr_code = $result;
-					$payment->qr_url = 'http://qr.topscan.com/api.php?text='.$result.'&bg=ffffff&fg=000000&pt=1c73bd&m=10&w=400&el=1&inpt=1eabfc&logo=https://t.alipayobjects.com/tfscom/T1Z5XfXdxmXXXXXXXX.png';
+					$payment->qr_code = $result['qr_code'];
+					$payment->qr_url = 'http://qr.topscan.com/api.php?text='.$result['qr_code'].'&bg=ffffff&fg=000000&pt=1c73bd&m=10&w=400&el=1&inpt=1eabfc&logo=https://t.alipayobjects.com/tfscom/T1Z5XfXdxmXXXXXXXX.png'; //后备:https://cli.im/api/qrcode/code?text=".$result['qr_code']."&mhid=5EfGCwztyckhMHcmI9ZcOKs
 					$payment->qr_local_url = $payment->qr_url;
 				}
 				$payment->status = 0;

+ 5 - 4
app/Http/Controllers/UserController.php

@@ -585,17 +585,18 @@ class UserController extends Controller
 		//付费用户判断
 		$view['not_paying_user'] = Order::uid()->where('status', 2)->where('is_expire', 0)->where('origin_amount', '>', 0)->doesntExist();
 		//客户端安装
-		$view['Shadowrocket_install'] = 'itms-services://?action=download-manifest&url='.self::$systemConfig['website_url'].'/clients/ipa.plist';
-		$view['Quantumult_install'] = 'itms-services://?action=download-manifest&url='.self::$systemConfig['website_url'].'/ipa.plist';
+		$view['Shadowrocket_install'] = 'itms-services://?action=download-manifest&url='.self::$systemConfig['website_url'].'/clients/Shadowrocket.plist';
+		$view['Quantumult_install'] = 'itms-services://?action=download-manifest&url='.self::$systemConfig['website_url'].'/clients/Quantumult.plist';
 		// 订阅连接
 		$subscribe = UserSubscribe::query()->where('user_id', Auth::user()->id)->first();
 		$view['subscribe_status'] = $subscribe->status;
 		$subscribe_link = (self::$systemConfig['subscribe_domain']? self::$systemConfig['subscribe_domain'] : self::$systemConfig['website_url']).'/s/'.$subscribe->code;
 		$view['link'] = $subscribe_link;
+		$view['subscribe_link'] ='sub://'.base64url_encode($subscribe_link);
 		$view['Shadowrocket_link'] = 'shadowrocket://add/sub://'.base64url_encode($subscribe_link).'?remarks='.(self::$systemConfig['website_name'].'-'.self::$systemConfig['website_url']);
 		$view['Shadowrocket_linkQrcode'] = 'sub://'.base64url_encode($subscribe_link).'#'.base64url_encode(self::$systemConfig['website_name']);
-		$view['Quantumult_linkOut'] = 'quantumult://configuration?server='.base64url_encode($subscribe_link).'&filter='.base64url_encode('https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/Pro.conf').'&rejection='.base64url_encode('https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/Rejection.conf');
-		$view['Quantumult_linkIn'] = 'quantumult://configuration?server='.base64url_encode($subscribe_link).'&filter='.base64url_encode('https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/BacktoCN.conf').'&rejection='.base64url_encode('https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/Rejection.conf');
+		$view['Quantumult_linkOut'] = 'quantumult://configuration?server='.base64url_encode($subscribe_link).'&filter='.base64url_encode('https://raw.githubusercontent.com/ZBrettonYe/VPN-Rules-Collection/master/Profiles/Quantumult/Pro.conf').'&rejection='.base64url_encode('https://raw.githubusercontent.com/ZBrettonYe/VPN-Rules-Collection/master/Profiles/Quantumult/Rejection.conf');
+		$view['Quantumult_linkIn'] = 'quantumult://configuration?server='.base64url_encode($subscribe_link).'&filter='.base64url_encode('https://raw.githubusercontent.com/ZBrettonYe/VPN-Rules-Collection/master/Profiles/Quantumult/BacktoCN.conf').'&rejection='.base64url_encode('https://raw.githubusercontent.com/ZBrettonYe/VPN-Rules-Collection/master/Profiles/Quantumult/Rejection.conf');
 
 		return Response::view('user.help', $view);
 	}

+ 108 - 107
composer.lock

@@ -481,16 +481,16 @@
         },
         {
             "name": "composer/spdx-licenses",
-            "version": "1.5.2",
+            "version": "1.5.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/composer/spdx-licenses.git",
-                "reference": "7ac1e6aec371357df067f8a688c3d6974df68fa5"
+                "reference": "0c3e51e1880ca149682332770e25977c70cf9dae"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/7ac1e6aec371357df067f8a688c3d6974df68fa5",
-                "reference": "7ac1e6aec371357df067f8a688c3d6974df68fa5",
+                "url": "https://api.github.com/repos/composer/spdx-licenses/zipball/0c3e51e1880ca149682332770e25977c70cf9dae",
+                "reference": "0c3e51e1880ca149682332770e25977c70cf9dae",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -543,7 +543,7 @@
                 "spdx",
                 "validator"
             ],
-            "time": "2019-07-29T10:31:59+00:00"
+            "time": "2020-02-14T07:44:31+00:00"
         },
         {
             "name": "composer/xdebug-handler",
@@ -1105,16 +1105,16 @@
         },
         {
             "name": "egulias/email-validator",
-            "version": "2.1.15",
+            "version": "2.1.17",
             "source": {
                 "type": "git",
                 "url": "https://github.com/egulias/EmailValidator.git",
-                "reference": "e834eea5306d85d67de5a05db5882911d5b29357"
+                "reference": "ade6887fd9bd74177769645ab5c474824f8a418a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/e834eea5306d85d67de5a05db5882911d5b29357",
-                "reference": "e834eea5306d85d67de5a05db5882911d5b29357",
+                "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ade6887fd9bd74177769645ab5c474824f8a418a",
+                "reference": "ade6887fd9bd74177769645ab5c474824f8a418a",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -1165,7 +1165,7 @@
                 "validation",
                 "validator"
             ],
-            "time": "2020-01-20T21:40:59+00:00"
+            "time": "2020-02-13T22:36:52+00:00"
         },
         {
             "name": "erusev/parsedown",
@@ -1274,16 +1274,16 @@
         },
         {
             "name": "fideloper/proxy",
-            "version": "4.2.2",
+            "version": "4.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/fideloper/TrustedProxy.git",
-                "reference": "790194d5d3da89a713478875d2e2d05855a90a81"
+                "reference": "ec38ad69ee378a1eec04fb0e417a97cfaf7ed11a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/fideloper/TrustedProxy/zipball/790194d5d3da89a713478875d2e2d05855a90a81",
-                "reference": "790194d5d3da89a713478875d2e2d05855a90a81",
+                "url": "https://api.github.com/repos/fideloper/TrustedProxy/zipball/ec38ad69ee378a1eec04fb0e417a97cfaf7ed11a",
+                "reference": "ec38ad69ee378a1eec04fb0e417a97cfaf7ed11a",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -1293,11 +1293,11 @@
                 ]
             },
             "require": {
-                "illuminate/contracts": "^5.0|^6.0|^7.0",
+                "illuminate/contracts": "^5.0|^6.0|^7.0|^8.0",
                 "php": ">=5.4.0"
             },
             "require-dev": {
-                "illuminate/http": "^5.0|^6.0|^7.0",
+                "illuminate/http": "^5.0|^6.0|^7.0|^8.0",
                 "mockery/mockery": "^1.0",
                 "phpunit/phpunit": "^6.0"
             },
@@ -1330,7 +1330,7 @@
                 "proxy",
                 "trusted proxy"
             ],
-            "time": "2019-12-20T13:11:11+00:00"
+            "time": "2020-02-22T01:51:47+00:00"
         },
         {
             "name": "guzzlehttp/guzzle",
@@ -1827,16 +1827,16 @@
         },
         {
             "name": "jaybizzle/crawler-detect",
-            "version": "v1.2.92",
+            "version": "v1.2.93",
             "source": {
                 "type": "git",
                 "url": "https://github.com/JayBizzle/Crawler-Detect.git",
-                "reference": "eb167049d7de1e5320138186b9dcb2e5f9df260d"
+                "reference": "608ec84bdf85fa8200c0f36f455483698b450ecd"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/JayBizzle/Crawler-Detect/zipball/eb167049d7de1e5320138186b9dcb2e5f9df260d",
-                "reference": "eb167049d7de1e5320138186b9dcb2e5f9df260d",
+                "url": "https://api.github.com/repos/JayBizzle/Crawler-Detect/zipball/608ec84bdf85fa8200c0f36f455483698b450ecd",
+                "reference": "608ec84bdf85fa8200c0f36f455483698b450ecd",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -1878,7 +1878,7 @@
                 "crawlerdetect",
                 "php crawler detect"
             ],
-            "time": "2020-02-07T20:28:07+00:00"
+            "time": "2020-02-16T12:34:48+00:00"
         },
         {
             "name": "jenssegers/agent",
@@ -2029,16 +2029,16 @@
         },
         {
             "name": "laravel/framework",
-            "version": "v5.8.36",
+            "version": "v5.8.37",
             "source": {
                 "type": "git",
                 "url": "https://github.com/laravel/framework.git",
-                "reference": "ccf857af50897eda43ceaf12e318cf214e0e4e95"
+                "reference": "ce08aaee3a0b8bb58b459b2decf7f25ba7b10fa4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/laravel/framework/zipball/ccf857af50897eda43ceaf12e318cf214e0e4e95",
-                "reference": "ccf857af50897eda43ceaf12e318cf214e0e4e95",
+                "url": "https://api.github.com/repos/laravel/framework/zipball/ce08aaee3a0b8bb58b459b2decf7f25ba7b10fa4",
+                "reference": "ce08aaee3a0b8bb58b459b2decf7f25ba7b10fa4",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -2179,7 +2179,7 @@
                 "framework",
                 "laravel"
             ],
-            "time": "2019-12-17T16:00:14+00:00"
+            "time": "2020-02-14T14:29:11+00:00"
         },
         {
             "name": "laravel/tinker",
@@ -2998,16 +2998,16 @@
         },
         {
             "name": "nesbot/carbon",
-            "version": "2.29.1",
+            "version": "2.30.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/briannesbitt/Carbon.git",
-                "reference": "e509be5bf2d703390e69e14496d9a1168452b0a2"
+                "reference": "912dff66d2690ca66abddb9b291a1df5f371d3b4"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/e509be5bf2d703390e69e14496d9a1168452b0a2",
-                "reference": "e509be5bf2d703390e69e14496d9a1168452b0a2",
+                "url": "https://api.github.com/repos/briannesbitt/Carbon/zipball/912dff66d2690ca66abddb9b291a1df5f371d3b4",
+                "reference": "912dff66d2690ca66abddb9b291a1df5f371d3b4",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -3070,7 +3070,7 @@
                 "datetime",
                 "time"
             ],
-            "time": "2020-01-21T09:36:43+00:00"
+            "time": "2020-02-07T15:25:46+00:00"
         },
         {
             "name": "nikic/php-parser",
@@ -3916,16 +3916,16 @@
         },
         {
             "name": "ramsey/uuid",
-            "version": "3.9.2",
+            "version": "3.9.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/ramsey/uuid.git",
-                "reference": "7779489a47d443f845271badbdcedfe4df8e06fb"
+                "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/ramsey/uuid/zipball/7779489a47d443f845271badbdcedfe4df8e06fb",
-                "reference": "7779489a47d443f845271badbdcedfe4df8e06fb",
+                "url": "https://api.github.com/repos/ramsey/uuid/zipball/7e1633a6964b48589b142d60542f9ed31bd37a92",
+                "reference": "7e1633a6964b48589b142d60542f9ed31bd37a92",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -4005,7 +4005,7 @@
                 "identifier",
                 "uuid"
             ],
-            "time": "2019-12-17T08:18:51+00:00"
+            "time": "2020-02-21T04:36:14+00:00"
         },
         {
             "name": "rap2hpoutre/laravel-log-viewer",
@@ -4192,16 +4192,16 @@
         },
         {
             "name": "seld/phar-utils",
-            "version": "1.0.2",
+            "version": "1.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/Seldaek/phar-utils.git",
-                "reference": "84715761c35808076b00908a20317a3a8a67d17e"
+                "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/84715761c35808076b00908a20317a3a8a67d17e",
-                "reference": "84715761c35808076b00908a20317a3a8a67d17e",
+                "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/8800503d56b9867d43d9c303b9cbcc26016e82f0",
+                "reference": "8800503d56b9867d43d9c303b9cbcc26016e82f0",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -4236,22 +4236,22 @@
             ],
             "description": "PHAR file format utilities, for when PHP phars you up",
             "keywords": [
-                "phra"
+                "phar"
             ],
-            "time": "2020-01-13T10:41:09+00:00"
+            "time": "2020-02-14T15:25:33+00:00"
         },
         {
             "name": "spatie/laravel-permission",
-            "version": "3.6.0",
+            "version": "3.8.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/spatie/laravel-permission.git",
-                "reference": "0a063ce206c7545737d19c1beda12003fc66e4e9"
+                "reference": "2339b6fae8f8aa5af047e1a0c54b6fb37546058a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/0a063ce206c7545737d19c1beda12003fc66e4e9",
-                "reference": "0a063ce206c7545737d19c1beda12003fc66e4e9",
+                "url": "https://api.github.com/repos/spatie/laravel-permission/zipball/2339b6fae8f8aa5af047e1a0c54b6fb37546058a",
+                "reference": "2339b6fae8f8aa5af047e1a0c54b6fb37546058a",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -4312,7 +4312,7 @@
                 "security",
                 "spatie"
             ],
-            "time": "2020-01-17T16:18:51+00:00"
+            "time": "2020-02-18T21:16:24+00:00"
         },
         {
             "name": "swiftmailer/swiftmailer",
@@ -5125,16 +5125,16 @@
         },
         {
             "name": "symfony/polyfill-ctype",
-            "version": "v1.13.1",
+            "version": "v1.14.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-ctype.git",
-                "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3"
+                "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
-                "reference": "f8f0b461be3385e56d6de3dbb5a0df24c0c275e3",
+                "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/fbdeaec0df06cf3d51c93de80c7eb76e271f5a38",
+                "reference": "fbdeaec0df06cf3d51c93de80c7eb76e271f5a38",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -5152,7 +5152,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.13-dev"
+                    "dev-master": "1.14-dev"
                 }
             },
             "autoload": {
@@ -5185,20 +5185,20 @@
                 "polyfill",
                 "portable"
             ],
-            "time": "2019-11-27T13:56:44+00:00"
+            "time": "2020-01-13T11:15:53+00:00"
         },
         {
             "name": "symfony/polyfill-iconv",
-            "version": "v1.13.1",
+            "version": "v1.14.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-iconv.git",
-                "reference": "a019efccc03f1a335af6b4f20c30f5ea8060be36"
+                "reference": "926832ce51059bb58211b7b2080a88e0c3b5328e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/a019efccc03f1a335af6b4f20c30f5ea8060be36",
-                "reference": "a019efccc03f1a335af6b4f20c30f5ea8060be36",
+                "url": "https://api.github.com/repos/symfony/polyfill-iconv/zipball/926832ce51059bb58211b7b2080a88e0c3b5328e",
+                "reference": "926832ce51059bb58211b7b2080a88e0c3b5328e",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -5216,7 +5216,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.13-dev"
+                    "dev-master": "1.14-dev"
                 }
             },
             "autoload": {
@@ -5250,20 +5250,20 @@
                 "portable",
                 "shim"
             ],
-            "time": "2019-11-27T13:56:44+00:00"
+            "time": "2020-01-13T11:15:53+00:00"
         },
         {
             "name": "symfony/polyfill-intl-idn",
-            "version": "v1.13.1",
+            "version": "v1.14.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-intl-idn.git",
-                "reference": "6f9c239e61e1b0c9229a28ff89a812dc449c3d46"
+                "reference": "6842f1a39cf7d580655688069a03dd7cd83d244a"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6f9c239e61e1b0c9229a28ff89a812dc449c3d46",
-                "reference": "6f9c239e61e1b0c9229a28ff89a812dc449c3d46",
+                "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/6842f1a39cf7d580655688069a03dd7cd83d244a",
+                "reference": "6842f1a39cf7d580655688069a03dd7cd83d244a",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -5275,7 +5275,7 @@
             "require": {
                 "php": ">=5.3.3",
                 "symfony/polyfill-mbstring": "^1.3",
-                "symfony/polyfill-php72": "^1.9"
+                "symfony/polyfill-php72": "^1.10"
             },
             "suggest": {
                 "ext-intl": "For best performance"
@@ -5283,7 +5283,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.13-dev"
+                    "dev-master": "1.14-dev"
                 }
             },
             "autoload": {
@@ -5318,20 +5318,20 @@
                 "portable",
                 "shim"
             ],
-            "time": "2019-11-27T13:56:44+00:00"
+            "time": "2020-01-17T12:01:36+00:00"
         },
         {
             "name": "symfony/polyfill-mbstring",
-            "version": "v1.13.1",
+            "version": "v1.14.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-mbstring.git",
-                "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f"
+                "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/7b4aab9743c30be783b73de055d24a39cf4b954f",
-                "reference": "7b4aab9743c30be783b73de055d24a39cf4b954f",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/34094cfa9abe1f0f14f48f490772db7a775559f2",
+                "reference": "34094cfa9abe1f0f14f48f490772db7a775559f2",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -5349,7 +5349,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.13-dev"
+                    "dev-master": "1.14-dev"
                 }
             },
             "autoload": {
@@ -5383,20 +5383,20 @@
                 "portable",
                 "shim"
             ],
-            "time": "2019-11-27T14:18:11+00:00"
+            "time": "2020-01-13T11:15:53+00:00"
         },
         {
             "name": "symfony/polyfill-php72",
-            "version": "v1.13.1",
+            "version": "v1.14.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php72.git",
-                "reference": "66fea50f6cb37a35eea048d75a7d99a45b586038"
+                "reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/66fea50f6cb37a35eea048d75a7d99a45b586038",
-                "reference": "66fea50f6cb37a35eea048d75a7d99a45b586038",
+                "url": "https://api.github.com/repos/symfony/polyfill-php72/zipball/46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf",
+                "reference": "46ecacf4751dd0dc81e4f6bf01dbf9da1dc1dadf",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -5411,7 +5411,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.13-dev"
+                    "dev-master": "1.14-dev"
                 }
             },
             "autoload": {
@@ -5444,20 +5444,20 @@
                 "portable",
                 "shim"
             ],
-            "time": "2019-11-27T13:56:44+00:00"
+            "time": "2020-01-13T11:15:53+00:00"
         },
         {
             "name": "symfony/polyfill-php73",
-            "version": "v1.13.1",
+            "version": "v1.14.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/symfony/polyfill-php73.git",
-                "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f"
+                "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/4b0e2222c55a25b4541305a053013d5647d3a25f",
-                "reference": "4b0e2222c55a25b4541305a053013d5647d3a25f",
+                "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/5e66a0fa1070bf46bec4bea7962d285108edd675",
+                "reference": "5e66a0fa1070bf46bec4bea7962d285108edd675",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -5472,7 +5472,7 @@
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "1.13-dev"
+                    "dev-master": "1.14-dev"
                 }
             },
             "autoload": {
@@ -5508,7 +5508,7 @@
                 "portable",
                 "shim"
             ],
-            "time": "2019-11-27T16:25:15+00:00"
+            "time": "2020-01-13T11:15:53+00:00"
         },
         {
             "name": "symfony/process",
@@ -6666,16 +6666,16 @@
         },
         {
             "name": "phpdocumentor/reflection-docblock",
-            "version": "4.3.4",
+            "version": "5.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
-                "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c"
+                "reference": "a48807183a4b819072f26e347bbd0b5199a9d15f"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/da3fd972d6bafd628114f7e7e036f45944b62e9c",
-                "reference": "da3fd972d6bafd628114f7e7e036f45944b62e9c",
+                "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/a48807183a4b819072f26e347bbd0b5199a9d15f",
+                "reference": "a48807183a4b819072f26e347bbd0b5199a9d15f",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -6685,28 +6685,25 @@
                 ]
             },
             "require": {
-                "php": "^7.0",
-                "phpdocumentor/reflection-common": "^1.0.0 || ^2.0.0",
-                "phpdocumentor/type-resolver": "~0.4 || ^1.0.0",
-                "webmozart/assert": "^1.0"
+                "ext-filter": "^7.1",
+                "php": "^7.2",
+                "phpdocumentor/reflection-common": "^2.0",
+                "phpdocumentor/type-resolver": "^1.0",
+                "webmozart/assert": "^1"
             },
             "require-dev": {
-                "doctrine/instantiator": "^1.0.5",
-                "mockery/mockery": "^1.0",
-                "phpdocumentor/type-resolver": "0.4.*",
-                "phpunit/phpunit": "^6.4"
+                "doctrine/instantiator": "^1",
+                "mockery/mockery": "^1"
             },
             "type": "library",
             "extra": {
                 "branch-alias": {
-                    "dev-master": "4.x-dev"
+                    "dev-master": "5.x-dev"
                 }
             },
             "autoload": {
                 "psr-4": {
-                    "phpDocumentor\\Reflection\\": [
-                        "src/"
-                    ]
+                    "phpDocumentor\\Reflection\\": "src"
                 }
             },
             "notification-url": "https://packagist.org/downloads/",
@@ -6717,10 +6714,14 @@
                 {
                     "name": "Mike van Riel",
                     "email": "me@mikevanriel.com"
+                },
+                {
+                    "name": "Jaap van Otterdijk",
+                    "email": "account@ijaap.nl"
                 }
             ],
             "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
-            "time": "2019-12-28T18:55:12+00:00"
+            "time": "2020-02-09T09:16:15+00:00"
         },
         {
             "name": "phpdocumentor/type-resolver",
@@ -7950,16 +7951,16 @@
         },
         {
             "name": "webmozart/assert",
-            "version": "1.6.0",
+            "version": "1.7.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/webmozart/assert.git",
-                "reference": "573381c0a64f155a0d9a23f4b0c797194805b925"
+                "reference": "aed98a490f9a8f78468232db345ab9cf606cf598"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/webmozart/assert/zipball/573381c0a64f155a0d9a23f4b0c797194805b925",
-                "reference": "573381c0a64f155a0d9a23f4b0c797194805b925",
+                "url": "https://api.github.com/repos/webmozart/assert/zipball/aed98a490f9a8f78468232db345ab9cf606cf598",
+                "reference": "aed98a490f9a8f78468232db345ab9cf606cf598",
                 "shasum": "",
                 "mirrors": [
                     {
@@ -8000,7 +8001,7 @@
                 "check",
                 "validate"
             ],
-            "time": "2019-11-24T13:36:37+00:00"
+            "time": "2020-02-14T12:15:55+00:00"
         }
     ],
     "aliases": [],

+ 354 - 0
public/assets/geetest/gt.js

@@ -0,0 +1,354 @@
+"v0.4.8 Geetest Inc.";
+
+(function (window) {
+    "use strict";
+    if (typeof window === 'undefined') {
+        throw new Error('Geetest requires browser environment');
+    }
+
+var document = window.document;
+var Math = window.Math;
+var head = document.getElementsByTagName("head")[0];
+
+function _Object(obj) {
+    this._obj = obj;
+}
+
+_Object.prototype = {
+    _each: function (process) {
+        var _obj = this._obj;
+        for (var k in _obj) {
+            if (_obj.hasOwnProperty(k)) {
+                process(k, _obj[k]);
+            }
+        }
+        return this;
+    }
+};
+
+function Config(config) {
+    var self = this;
+    new _Object(config)._each(function (key, value) {
+        self[key] = value;
+    });
+}
+
+Config.prototype = {
+    api_server: 'api.geetest.com',
+    protocol: 'http://',
+    typePath: '/gettype.php',
+    fallback_config: {
+        slide: {
+            static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
+            type: 'slide',
+            slide: '/static/js/geetest.0.0.0.js'
+        },
+        fullpage: {
+            static_servers: ["static.geetest.com", "dn-staticdown.qbox.me"],
+            type: 'fullpage',
+            fullpage: '/static/js/fullpage.0.0.0.js'
+        }
+    },
+    _get_fallback_config: function () {
+        var self = this;
+        if (isString(self.type)) {
+            return self.fallback_config[self.type];
+        } else if (self.new_captcha) {
+            return self.fallback_config.fullpage;
+        } else {
+            return self.fallback_config.slide;
+        }
+    },
+    _extend: function (obj) {
+        var self = this;
+        new _Object(obj)._each(function (key, value) {
+            self[key] = value;
+        })
+    }
+};
+var isNumber = function (value) {
+    return (typeof value === 'number');
+};
+var isString = function (value) {
+    return (typeof value === 'string');
+};
+var isBoolean = function (value) {
+    return (typeof value === 'boolean');
+};
+var isObject = function (value) {
+    return (typeof value === 'object' && value !== null);
+};
+var isFunction = function (value) {
+    return (typeof value === 'function');
+};
+var MOBILE = /Mobi/i.test(navigator.userAgent);
+var pt = MOBILE ? 3 : 0;
+
+var callbacks = {};
+var status = {};
+
+var nowDate = function () {
+    var date = new Date();
+    var year = date.getFullYear();
+    var month = date.getMonth() + 1;
+    var day = date.getDate();
+    var hours = date.getHours();
+    var minutes = date.getMinutes();
+    var seconds = date.getSeconds();
+
+    if (month >= 1 && month <= 9) {
+      month = '0' + month;
+    }
+    if (day >= 0 && day <= 9) {
+      day = '0' + day;
+    }
+    if (hours >= 0 && hours <= 9) {
+      hours = '0' + hours;
+    }
+    if (minutes >= 0 && minutes <= 9) {
+      minutes = '0' + minutes;
+    }
+    if (seconds >= 0 && seconds <= 9) {
+      seconds = '0' + seconds;
+    }
+    var currentdate = year + '-' + month + '-' + day + " " + hours + ":" + minutes + ":" + seconds;
+    return currentdate;
+}
+
+var random = function () {
+    return parseInt(Math.random() * 10000) + (new Date()).valueOf();
+};
+
+var loadScript = function (url, cb) {
+    var script = document.createElement("script");
+    script.charset = "UTF-8";
+    script.async = true;
+
+    // 对geetest的静态资源添加 crossOrigin
+    if ( /static\.geetest\.com/g.test(url)) {
+        script.crossOrigin = "anonymous";
+    }
+
+    script.onerror = function () {
+        cb(true);
+    };
+    var loaded = false;
+    script.onload = script.onreadystatechange = function () {
+        if (!loaded &&
+            (!script.readyState ||
+            "loaded" === script.readyState ||
+            "complete" === script.readyState)) {
+
+            loaded = true;
+            setTimeout(function () {
+                cb(false);
+            }, 0);
+        }
+    };
+    script.src = url;
+    head.appendChild(script);
+};
+
+var normalizeDomain = function (domain) {
+    // special domain: uems.sysu.edu.cn/jwxt/geetest/
+    // return domain.replace(/^https?:\/\/|\/.*$/g, ''); uems.sysu.edu.cn
+    return domain.replace(/^https?:\/\/|\/$/g, ''); // uems.sysu.edu.cn/jwxt/geetest
+};
+var normalizePath = function (path) {
+    path = path.replace(/\/+/g, '/');
+    if (path.indexOf('/') !== 0) {
+        path = '/' + path;
+    }
+    return path;
+};
+var normalizeQuery = function (query) {
+    if (!query) {
+        return '';
+    }
+    var q = '?';
+    new _Object(query)._each(function (key, value) {
+        if (isString(value) || isNumber(value) || isBoolean(value)) {
+            q = q + encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&';
+        }
+    });
+    if (q === '?') {
+        q = '';
+    }
+    return q.replace(/&$/, '');
+};
+var makeURL = function (protocol, domain, path, query) {
+    domain = normalizeDomain(domain);
+
+    var url = normalizePath(path) + normalizeQuery(query);
+    if (domain) {
+        url = protocol + domain + url;
+    }
+
+    return url;
+};
+
+var load = function (config, send, protocol, domains, path, query, cb) {
+    var tryRequest = function (at) {
+
+        var url = makeURL(protocol, domains[at], path, query);
+        loadScript(url, function (err) {
+            if (err) {
+                if (at >= domains.length - 1) {
+                    cb(true);
+                    // report gettype error
+                    if (send) {
+                        config.error_code = 508;
+                        var url = protocol + domains[at] + path;
+                        reportError(config, url);
+                    }
+                } else {
+                    tryRequest(at + 1);
+                }
+            } else {
+                cb(false);
+            }
+        });
+    };
+    tryRequest(0);
+};
+
+
+var jsonp = function (domains, path, config, callback) {
+    if (isObject(config.getLib)) {
+        config._extend(config.getLib);
+        callback(config);
+        return;
+    }
+    if (config.offline) {
+        callback(config._get_fallback_config());
+        return;
+    }
+
+    var cb = "geetest_" + random();
+    window[cb] = function (data) {
+        if (data.status == 'success') {
+            callback(data.data);
+        } else if (!data.status) {
+            callback(data);
+        } else {
+            callback(config._get_fallback_config());
+        }
+        window[cb] = undefined;
+        try {
+            delete window[cb];
+        } catch (e) {
+        }
+    };
+    load(config, true, config.protocol, domains, path, {
+        gt: config.gt,
+        callback: cb
+    }, function (err) {
+        if (err) {
+            callback(config._get_fallback_config());
+        }
+    });
+};
+
+var reportError = function (config, url) {
+    load(config, false, config.protocol, ['monitor.geetest.com'], '/monitor/send', {
+        time: nowDate(),
+        captcha_id: config.gt,
+        challenge: config.challenge,
+        pt: pt,
+        exception_url: url,
+        error_code: config.error_code
+    }, function (err) {})
+}
+
+var throwError = function (errorType, config) {
+    var errors = {
+        networkError: '网络错误',
+        gtTypeError: 'gt字段不是字符串类型'
+    };
+    if (typeof config.onError === 'function') {
+        config.onError(errors[errorType]);
+    } else {
+        throw new Error(errors[errorType]);
+    }
+};
+
+var detect = function () {
+    return window.Geetest || document.getElementById("gt_lib");
+};
+
+if (detect()) {
+    status.slide = "loaded";
+}
+
+window.initGeetest = function (userConfig, callback) {
+
+    var config = new Config(userConfig);
+
+    if (userConfig.https) {
+        config.protocol = 'https://';
+    } else if (!userConfig.protocol) {
+        config.protocol = window.location.protocol + '//';
+    }
+
+    // for KFC
+    if (userConfig.gt === '050cffef4ae57b5d5e529fea9540b0d1' ||
+        userConfig.gt === '3bd38408ae4af923ed36e13819b14d42') {
+        config.apiserver = 'yumchina.geetest.com/'; // for old js
+        config.api_server = 'yumchina.geetest.com';
+    }
+
+    if(userConfig.gt){
+        window.GeeGT = userConfig.gt
+    }
+
+    if(userConfig.challenge){
+        window.GeeChallenge = userConfig.challenge
+    }
+
+    if (isObject(userConfig.getType)) {
+        config._extend(userConfig.getType);
+    }
+    jsonp([config.api_server || config.apiserver], config.typePath, config, function (newConfig) {
+        var type = newConfig.type;
+        var init = function () {
+            config._extend(newConfig);
+            callback(new window.Geetest(config));
+        };
+
+        callbacks[type] = callbacks[type] || [];
+        var s = status[type] || 'init';
+        if (s === 'init') {
+            status[type] = 'loading';
+
+            callbacks[type].push(init);
+
+            load(config, true, config.protocol, newConfig.static_servers || newConfig.domains, newConfig[type] || newConfig.path, null, function (err) {
+                if (err) {
+                    status[type] = 'fail';
+                    throwError('networkError', config);
+                } else {
+                    status[type] = 'loaded';
+                    var cbs = callbacks[type];
+                    for (var i = 0, len = cbs.length; i < len; i = i + 1) {
+                        var cb = cbs[i];
+                        if (isFunction(cb)) {
+                            cb();
+                        }
+                    }
+                    callbacks[type] = [];
+                }
+            });
+        } else if (s === "loaded") {
+            init();
+        } else if (s === "fail") {
+            throwError('networkError', config);
+        } else if (s === "loading") {
+            callbacks[type].push(init);
+        }
+    });
+
+};
+
+
+})(window);
+

+ 17 - 0
resources/views/admin/nodeList.blade.php

@@ -1,6 +1,11 @@
 @extends('admin.layouts')
 @section('css')
 	<link href="/assets/global/vendor/bootstrap-table/bootstrap-table.min.css" type="text/css" rel="stylesheet">
+	<style>
+		#swal2-content{
+			display:grid !important;
+		}
+	</style>
 @endsection
 @section('content')
 	<div class="page-content container-fluid">
@@ -62,6 +67,7 @@
 								</td>
 								<td>
 									<div class="btn-group">
+										<a href="javascript:testNode('{{$node->id}}','{{$node->name}}')" class="btn btn-primary"><i class="icon wb-signal"></i></a>
 										<a href="/admin/editNode?id={{$node->id}}&page={{Request::get('page', 1)}}" class="btn btn-primary"><i class="icon wb-edit"></i></a>
 										<a href="javascript:delNode('{{$node->id}}','{{$node->name}}')" class="btn btn-danger"><i class="icon wb-trash"></i></a>
 										<a href="/admin/nodeMonitor/{{$node->id}})" class="btn btn-primary"><i class="icon wb-stats-bars"></i></a>
@@ -92,6 +98,17 @@
 	<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">
+        //节点连通性测试
+        function testNode(id, name) {
+            $.post("/admin/nodeList", {id: id, _token: '{{csrf_token()}}'}, function (ret) {
+                if (ret.status === 'success') {
+                    swal.fire({title: ret.title, type: 'info', html: '<table class="my-20"><thead class="thead-default"><tr><th> ICMP </th> <th> TCP </th></thead><tbody><tr><td>' + ret.message[0] + '</td><td>' + ret.message[1] + '</td></tr></tbody></table>', showConfirmButton: false})
+                } else {
+                    swal.fire({title: ret.title, type: "error"})
+                }
+            });
+        }
+
         // 删除节点
         function delNode(id, name) {
             swal.fire({

+ 1 - 1
resources/views/admin/system.blade.php

@@ -1072,7 +1072,7 @@
 
         // 需要检查限制的更新
         function updateFromInput(systemItem, lowerBound, upperBound) {
-            let value = $('#' + systemItem).val();
+            let value = parseInt($('#' + systemItem).val());
             if (lowerBound !== false && value < lowerBound) {
                 swal.fire({title: '不能小于' + lowerBound, type: 'warning', timer: 1000, showConfirmButton: false});
             } else if (upperBound !== false && value > upperBound) {

+ 2 - 2
resources/views/vendor/geetest/geetest.blade.php

@@ -1,5 +1,5 @@
-<script src="//cdn.bootcss.com/jquery/2.1.0/jquery.min.js" type="text/javascript"></script>
-<script src="//static.geetest.com/static/tools/gt.js" type="text/javascript"></script>
+<script src="https://cdnjs.loli.net/ajax/libs/jquery/2.1.0/jquery.min.js" type="text/javascript"></script>
+<script src="/assets/geetest/gt.js" type="text/javascript"></script>
 <div id="{{ $captchaid }}"></div>
 <p id="wait-{{ $captchaid }}" class="show">{{trans('auth.captcha_loading')}}</p>
 @define use Illuminate\Support\Facades\Config

+ 1 - 1
routes/web.php

@@ -26,7 +26,7 @@ Route::group(['middleware' => ['isForbidden', 'isLogin', 'isAdmin']], function()
 	Route::post('admin/delUser', 'AdminController@delUser'); // 删除账号
 	Route::post('admin/batchAddUsers', 'AdminController@batchAddUsers'); // 批量生成账号
 	Route::get('admin/exportSSJson', 'AdminController@exportSSJson'); // 导出原版SS的json配置信息
-	Route::get('admin/nodeList', 'AdminController@nodeList'); // 节点列表
+	Route::any('admin/nodeList', 'AdminController@nodeList'); // 节点列表
 	Route::any('admin/addNode', 'AdminController@addNode'); // 添加节点
 	Route::any('admin/editNode', 'AdminController@editNode'); // 编辑节点
 	Route::post('admin/delNode', 'AdminController@delNode'); // 删除节点