diff --git a/.env.example b/.env.example index c46aa9ff..4526ed68 100644 --- a/.env.example +++ b/.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= diff --git a/app/Http/Controllers/Admin/RuleController.php b/app/Http/Controllers/Admin/RuleController.php index 066faa5d..e2cc591f 100644 --- a/app/Http/Controllers/Admin/RuleController.php +++ b/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)]); - } - RuleGroupNode::query()->whereRuleGroupId($id)->delete(); - foreach($nodes as $nodeId){ - $obj = new RuleGroupNode(); - $obj->rule_group_id = $id; - $obj->node_id = $nodeId; - $obj->save(); + try{ + 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(); } + }catch(Exception $e){ return Redirect::back()->withInput()->withErrors($e->getMessage()); } diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index c0cbb763..b456afd5 100644 --- a/app/Http/Controllers/AdminController.php +++ b/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); diff --git a/app/Http/Controllers/Api/V2Ray/V1Controller.php b/app/Http/Controllers/Api/V2Ray/V1Controller.php new file mode 100644 index 00000000..7e1a893b --- /dev/null +++ b/app/Http/Controllers/Api/V2Ray/V1Controller.php @@ -0,0 +1,333 @@ +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' => '上报节点伪装域名证书失败,请检查字段' + ]); + } +} diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 114a4865..9880e172 100644 --- a/app/Http/Controllers/Controller.php +++ b/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; diff --git a/app/Http/Controllers/NodeController.php b/app/Http/Controllers/NodeController.php index 73aa0ccd..0a389e53 100644 --- a/app/Http/Controllers/NodeController.php +++ b/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' => '操作失败']); + } + } } diff --git a/app/Http/Controllers/PaymentController.php b/app/Http/Controllers/PaymentController.php index a2c2822b..8448def7 100644 --- a/app/Http/Controllers/PaymentController.php +++ b/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){ diff --git a/app/Http/Controllers/User/SubscribeController.php b/app/Http/Controllers/User/SubscribeController.php index 125f84f1..50154277 100644 --- a/app/Http/Controllers/User/SubscribeController.php +++ b/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 = [ diff --git a/app/Http/Controllers/UserController.php b/app/Http/Controllers/UserController.php index 88504211..1d88c5f3 100644 --- a/app/Http/Controllers/UserController.php +++ b/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{ diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index ff87d277..b386ba6b 100644 --- a/app/Http/Kernel.php +++ b/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, + ]; } diff --git a/app/Http/Middleware/Authenticate.php b/app/Http/Middleware/Authenticate.php new file mode 100644 index 00000000..888fdf21 --- /dev/null +++ b/app/Http/Middleware/Authenticate.php @@ -0,0 +1,19 @@ +expectsJson()){ + return route('login'); + } + } +} diff --git a/app/Http/Middleware/RedirectIfAuthenticated.php b/app/Http/Middleware/RedirectIfAuthenticated.php index cb5591b9..4019fda1 100644 --- a/app/Http/Middleware/RedirectIfAuthenticated.php +++ b/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('/'); } diff --git a/app/Http/Middleware/TrustProxies.php b/app/Http/Middleware/TrustProxies.php index 879a20e2..80c95e0e 100644 --- a/app/Http/Middleware/TrustProxies.php +++ b/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; } diff --git a/app/Http/Middleware/VerifyCsrfToken.php b/app/Http/Middleware/VerifyCsrfToken.php index 7d54d17e..1aa2eb15 100644 --- a/app/Http/Middleware/VerifyCsrfToken.php +++ b/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. * diff --git a/app/Http/Middleware/WebApi.php b/app/Http/Middleware/WebApi.php index 5fb8d4ea..82e89a8b 100644 --- a/app/Http/Middleware/WebApi.php +++ b/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([ - 'ret' => 0, - 'data' => 'Your key is null' + "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" ]); } - if(!in_array($key, env('WEB_API_KEY'))){ - // key 不存在 + $node = SsNode::query()->whereId($id)->first(); + if(!$node){// node不存在 return Response::json([ - 'ret' => 0, - 'data' => 'Token is invalid' + "status" => "fail", + "code" => 404, + "data" => "", + "message" => "Unknown Node" ]); } - if(env('WEB_API') == false){ - // 主站不提供 Webapi + $nodeAuth = NodeAuth::query()->whereNodeId($id)->first(); + if(!$nodeAuth || $key != $nodeAuth->key){// key不存在/不匹配 return Response::json([ - 'ret' => 0, - 'data' => 'We regret this service is temporarily unavailable' + "status" => "fail", + "code" => 404, + "data" => "", + "message" => "Token is invalid" + ]); + } + + if(abs($time - time()) >= 300){//时差超过5分钟 + return Response::json([ + "status" => "fail", + "code" => 404, + "data" => "", + "message" => "Please resynchronize the server time!" ]); } diff --git a/app/Models/Article.php b/app/Models/Article.php index 3f67e200..030caf5a 100644 --- a/app/Models/Article.php +++ b/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 最后更新时间 diff --git a/app/Models/Goods.php b/app/Models/Goods.php index ca2fdeaa..ca0de3c4 100644 --- a/app/Models/Goods.php +++ b/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 有效期 diff --git a/app/Models/Invite.php b/app/Models/Invite.php index cf557dd8..1e5cd482 100644 --- a/app/Models/Invite.php +++ b/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; diff --git a/app/Models/NodeAuth.php b/app/Models/NodeAuth.php new file mode 100644 index 00000000..bb9ac384 --- /dev/null +++ b/app/Models/NodeAuth.php @@ -0,0 +1,36 @@ +hasOne(SsNode::class, 'id', 'node_id'); + } +} diff --git a/app/Models/NodeCertificate.php b/app/Models/NodeCertificate.php new file mode 100644 index 00000000..fcd7cec3 --- /dev/null +++ b/app/Models/NodeCertificate.php @@ -0,0 +1,31 @@ +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; + } } diff --git a/app/Models/RuleGroup.php b/app/Models/RuleGroup.php index 0523895f..1946c4ff 100644 --- a/app/Models/RuleGroup.php +++ b/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,多个用,号分隔 diff --git a/app/Models/SsNode.php b/app/Models/SsNode.php index 6bc2757d..3cc6e0f8 100644 --- a/app/Models/SsNode.php +++ b/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; + } } diff --git a/app/Models/SsNodeIp.php b/app/Models/SsNodeIp.php index f03bd61c..f23d31ca 100644 --- a/app/Models/SsNodeIp.php +++ b/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'); } } diff --git a/app/Models/UserTrafficLog.php b/app/Models/UserTrafficLog.php index e3dce531..e50721cf 100644 --- a/app/Models/UserTrafficLog.php +++ b/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'); } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index ecf758e7..0d2f7e13 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -7,6 +7,18 @@ use Illuminate\Support\ServiceProvider; use URL; class AppServiceProvider extends ServiceProvider { + + /** + * Register any application services. + * + * @return void + */ + public function register() { + if($this->app->environment() !== 'production'){ + $this->app->register(IdeHelperServiceProvider::class); + } + } + /** * Bootstrap any application services. * @@ -20,15 +32,4 @@ class AppServiceProvider extends ServiceProvider { //\Schema::defaultStringLength(191); } - - /** - * Register any application services. - * - * @return void - */ - public function register() { - if($this->app->environment() !== 'production'){ - $this->app->register(IdeHelperServiceProvider::class); - } - } } diff --git a/app/Providers/AuthServiceProvider.php b/app/Providers/AuthServiceProvider.php index e7a8cfc6..3c932350 100644 --- a/app/Providers/AuthServiceProvider.php +++ b/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', ]; /** diff --git a/bootstrap/app.php b/bootstrap/app.php index 9c879ffe..037e17df 100644 --- a/bootstrap/app.php +++ b/bootstrap/app.php @@ -12,7 +12,7 @@ */ $app = new Illuminate\Foundation\Application( - realpath(__DIR__ . '/../') + $_ENV['APP_BASE_PATH'] ?? dirname(__DIR__) ); /* diff --git a/composer.json b/composer.json index 1603dc54..1593dd91 100644 --- a/composer.json +++ b/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" - }, - "autoload": { - "files": [ - "app/helpers.php" - ], - "classmap": [ - "database/seeds", - "database/factories" - ], - "psr-4": { - "App\\": "app/" - } - }, - "autoload-dev": { - "psr-4": { - "Tests\\": "tests/" - } - }, - "extra": { - "laravel": { - "dont-discover": [ - ] - } - }, - "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" - ] + "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": { - "preferred-install": "dist", - "sort-packages": true, - "optimize-autoloader": true + "optimize-autoloader": true, + "preferred-install": "dist", + "sort-packages": true }, - "repositories": { - "packagist": { - "type": "composer", - "url": "https://mirrors.aliyun.com/composer/" - } + "extra": { + "laravel": { + "dont-discover": [] + } + }, + "autoload": { + "psr-4": { + "App\\": "app/" + }, + "classmap": [ + "database/seeds", + "database/factories" + ], + "files": [ + "app/helpers.php" + ] + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } }, "minimum-stability": "dev", - "prefer-stable": true + "prefer-stable": true, + "scripts": { + "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/" + } + } } diff --git a/composer.lock b/composer.lock index 29057355..664d9816 100644 --- a/composer.lock +++ b/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", diff --git a/config/app.php b/config/app.php index 7407db2e..3cead92a 100644 --- a/config/app.php +++ b/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, + ], ]; diff --git a/config/auth.php b/config/auth.php index 087bbb3e..86a0ea13 100644 --- a/config/auth.php +++ b/config/auth.php @@ -44,6 +44,7 @@ return [ 'api' => [ 'driver' => 'token', 'provider' => 'users', + 'hash' => false, ], ], diff --git a/config/broadcasting.php b/config/broadcasting.php index 5b0ae815..3bba1103 100644 --- a/config/broadcasting.php +++ b/config/broadcasting.php @@ -37,7 +37,7 @@ return [ 'app_id' => env('PUSHER_APP_ID'), 'options' => [ 'cluster' => env('PUSHER_APP_CLUSTER'), - 'encrypted' => TRUE, + 'useTLS' => true, ], ], diff --git a/config/cache.php b/config/cache.php index 7285bf19..46751e62 100644 --- a/config/cache.php +++ b/config/cache.php @@ -1,5 +1,7 @@ [ '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'), ]; diff --git a/config/captcha.php b/config/captcha.php index a782a8b1..da5e0a01 100644 --- a/config/captcha.php +++ b/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' => [ diff --git a/config/database.php b/config/database.php index ba0ff7d8..acafbdbf 100644 --- a/config/database.php +++ b/config/database.php @@ -1,5 +1,7 @@ [ '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), + 'password' => env('REDIS_PASSWORD', null), 'port' => env('REDIS_PORT', 6379), - 'database' => 0, + 'database' => env('REDIS_DB', 0), + ], + + 'cache' => [ + '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_CACHE_DB', 1), ], ], diff --git a/config/domains.php b/config/domains.php index 6806415b..7056a02c 100644 --- a/config/domains.php +++ b/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' ]; diff --git a/config/filesystems.php b/config/filesystems.php index 443f2934..77fa5ded 100644 --- a/config/filesystems.php +++ b/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', ], diff --git a/config/hashing.php b/config/hashing.php index d3c8e2fb..84257708 100644 --- a/config/hashing.php +++ b/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" | */ diff --git a/config/logging.php b/config/logging.php index 400bc7f4..d09cd7d2 100644 --- a/config/logging.php +++ b/config/logging.php @@ -1,6 +1,7 @@ [ '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', ], diff --git a/config/mail.php b/config/mail.php index 2a364f47..6f8469f8 100644 --- a/config/mail.php +++ b/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'), ]; diff --git a/config/permission.php b/config/permission.php index 4c2ebab3..1a0b35a2 100644 --- a/config/permission.php +++ b/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', ], ]; diff --git a/config/queue.php b/config/queue.php index 2f41a66d..07c7d2a9 100644 --- a/config/queue.php +++ b/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, ], ], diff --git a/config/services.php b/config/services.php index aa1f7f82..8ce6cc63 100644 --- a/config/services.php +++ b/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'), - ], - ]; diff --git a/config/session.php b/config/session.php index d8ffcccf..fbb9b4d7 100644 --- a/config/session.php +++ b/config/session.php @@ -1,5 +1,7 @@ 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, ]; diff --git a/config/view.php b/config/view.php index 2acfd9cc..22b8a18d 100644 --- a/config/view.php +++ b/config/view.php @@ -28,6 +28,9 @@ return [ | */ - 'compiled' => realpath(storage_path('framework/views')), + 'compiled' => env( + 'VIEW_COMPILED_PATH', + realpath(storage_path('framework/views')) + ), ]; diff --git a/database/.gitignore b/database/.gitignore index 9b1dffd9..97fc9767 100644 --- a/database/.gitignore +++ b/database/.gitignore @@ -1 +1,2 @@ *.sqlite +*.sqlite-journal diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index facf2337..5e516cee 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -1,5 +1,8 @@ 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), ]; }); diff --git a/package.json b/package.json index e81ab87f..bf85f38e 100644 --- a/package.json +++ b/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" } } diff --git a/phpunit.xml b/phpunit.xml index f564cfb6..da4add30 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -23,11 +23,11 @@ - - - - - - + + + + + + diff --git a/public/assets/images/noimage.png b/public/assets/images/noimage.png new file mode 100644 index 00000000..71484a82 Binary files /dev/null and b/public/assets/images/noimage.png differ diff --git a/public/assets/images/payment/alipay.png b/public/assets/images/payment/alipay.png new file mode 100644 index 00000000..b6d3fa38 Binary files /dev/null and b/public/assets/images/payment/alipay.png differ diff --git a/public/assets/images/payment/pp-logo-150px.png b/public/assets/images/payment/pp-logo-150px.png new file mode 100644 index 00000000..e8c641ec Binary files /dev/null and b/public/assets/images/payment/pp-logo-150px.png differ diff --git a/public/assets/images/payment/wechat.png b/public/assets/images/payment/wechat.png new file mode 100644 index 00000000..d269fb90 Binary files /dev/null and b/public/assets/images/payment/wechat.png differ diff --git a/public/web.config b/public/web.config index 624c1760..d3711d7c 100644 --- a/public/web.config +++ b/public/web.config @@ -1,3 +1,8 @@ + diff --git a/resources/assets/js/components/Example.vue b/resources/assets/js/components/Example.vue deleted file mode 100644 index 19b62a05..00000000 --- a/resources/assets/js/components/Example.vue +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/resources/assets/js/components/ExampleComponent.vue b/resources/assets/js/components/ExampleComponent.vue deleted file mode 100644 index 2665ac16..00000000 --- a/resources/assets/js/components/ExampleComponent.vue +++ /dev/null @@ -1,23 +0,0 @@ - - - diff --git a/resources/assets/js/app.js b/resources/js/app.js similarity index 53% rename from resources/assets/js/app.js rename to resources/js/app.js index 4a316b15..a1efb5c3 100644 --- a/resources/assets/js/app.js +++ b/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 -> + */ + +// 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', }); diff --git a/resources/assets/js/bootstrap.js b/resources/js/bootstrap.js similarity index 65% rename from resources/assets/js/bootstrap.js rename to resources/js/bootstrap.js index f1d7e744..8eaba1b9 100644 --- a/resources/assets/js/bootstrap.js +++ b/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'); diff --git a/resources/js/components/ExampleComponent.vue b/resources/js/components/ExampleComponent.vue new file mode 100644 index 00000000..3fb9f9aa --- /dev/null +++ b/resources/js/components/ExampleComponent.vue @@ -0,0 +1,23 @@ + + + diff --git a/resources/assets/sass/_variables.scss b/resources/sass/_variables.scss similarity index 80% rename from resources/assets/sass/_variables.scss rename to resources/sass/_variables.scss index 490c3c8a..0407ab57 100644 --- a/resources/assets/sass/_variables.scss +++ b/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; diff --git a/resources/assets/sass/app.scss b/resources/sass/app.scss similarity index 63% rename from resources/assets/sass/app.scss rename to resources/sass/app.scss index ef7eafeb..3193ffa2 100644 --- a/resources/assets/sass/app.scss +++ b/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); -} diff --git a/resources/views/admin/article/articleList.blade.php b/resources/views/admin/article/articleList.blade.php index cd9ebf6b..8f98e098 100644 --- a/resources/views/admin/article/articleList.blade.php +++ b/resources/views/admin/article/articleList.blade.php @@ -40,7 +40,7 @@ @endif {{\Illuminate\Support\Str::limit($vo->title, 80)}} + target="_blank"> {{Str::limit($vo->title, 80)}} {{$vo->sort}} {{$vo->created_at}} diff --git a/resources/views/admin/config/system.blade.php b/resources/views/admin/config/system.blade.php index 7e60f7f2..7959409e 100644 --- a/resources/views/admin/config/system.blade.php +++ b/resources/views/admin/config/system.blade.php @@ -455,6 +455,45 @@ 启用后,订阅信息顶部将显示过期时间、剩余流量(Quantumult有特殊效果) +
+
+ +
+
+ + + + +
+
+
+
+
+
+ +
+
+ + + + +
+
+
+
+
+
+ +
+
+ + + + +
+
+
+
diff --git a/resources/views/admin/coupon/addCoupon.blade.php b/resources/views/admin/coupon/addCoupon.blade.php index 6e960702..aa45d766 100644 --- a/resources/views/admin/coupon/addCoupon.blade.php +++ b/resources/views/admin/coupon/addCoupon.blade.php @@ -15,7 +15,7 @@

生成卡券

@if (Session::has('successMsg')) diff --git a/resources/views/admin/coupon/couponList.blade.php b/resources/views/admin/coupon/couponList.blade.php index fe6696c5..8ede3877 100644 --- a/resources/views/admin/coupon/couponList.blade.php +++ b/resources/views/admin/coupon/couponList.blade.php @@ -35,7 +35,7 @@
- 重 置 + 重 置
@@ -116,8 +116,7 @@ @endsection @section('script') - + + + + +@endsection \ No newline at end of file diff --git a/resources/views/admin/node/nodeInfo.blade.php b/resources/views/admin/node/nodeInfo.blade.php index 23c1effe..81b61b8e 100644 --- a/resources/views/admin/node/nodeInfo.blade.php +++ b/resources/views/admin/node/nodeInfo.blade.php @@ -57,10 +57,9 @@ placeholder="服务器IPv6地址,填写则用户可见,域名无效">
- - - 请务必正确填写此值,否则TCP阻断检测可能误报 + + + 必填且防火墙需放行,否则将导致消息推送异常
@@ -290,19 +289,12 @@
- -