mirror of
https://github.com/lkddi/nexusphp.git
synced 2026-04-26 05:17:22 +08:00
[admin] agent allow&deny
This commit is contained in:
@@ -11,6 +11,7 @@ use App\Models\Medal;
|
||||
use App\Models\SearchBox;
|
||||
use App\Models\Snatch;
|
||||
use App\Models\User;
|
||||
use App\Repositories\AgentAllowRepository;
|
||||
use App\Repositories\ExamRepository;
|
||||
use App\Repositories\HitAndRunRepository;
|
||||
use App\Repositories\SearchBoxRepository;
|
||||
@@ -58,8 +59,10 @@ class Test extends Command
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$rep = new HitAndRunRepository();
|
||||
$r = $rep->cronjobUpdateStatus();
|
||||
$peerId = '-TR2920-9bqp8iu7v9se';
|
||||
$agent = 'Transmission/2.92';
|
||||
$rep = new AgentAllowRepository();
|
||||
$r = $rep->checkClient($peerId, $agent, true);
|
||||
dd($r);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,18 +4,47 @@ namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Resources\AgentAllowResource;
|
||||
use App\Models\AgentAllow;
|
||||
use App\Repositories\AgentAllowRepository;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class AgentAllowController extends Controller
|
||||
{
|
||||
private $repository;
|
||||
|
||||
public function __construct(AgentAllowRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
private function getRules(): array
|
||||
{
|
||||
return [
|
||||
'family' => 'required|string',
|
||||
'start_name' => 'required|string',
|
||||
|
||||
'peer_id_pattern' => 'required|string',
|
||||
'peer_id_match_num' => 'required|numeric',
|
||||
'peer_id_matchtype' => ['required', Rule::in(array_keys(AgentAllow::$matchTypes))],
|
||||
'peer_id_start' => 'required|string',
|
||||
|
||||
'agent_pattern' => 'required|string',
|
||||
'agent_match_num' => 'required|numeric',
|
||||
'agent_matchtype' => ['required', Rule::in(array_keys(AgentAllow::$matchTypes))],
|
||||
'agent_start' => 'required|string',
|
||||
|
||||
'exception' => ['required', Rule::in(['yes', 'no'])],
|
||||
'allowhttps' => ['required', Rule::in(['yes', 'no'])],
|
||||
];
|
||||
}
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function index()
|
||||
public function index(Request $request)
|
||||
{
|
||||
$result = AgentAllow::query()->orderBy('id', 'desc')->paginate();
|
||||
$result = $this->repository->getList($request->all());
|
||||
$resource = AgentAllowResource::collection($result);
|
||||
return $this->success($resource);
|
||||
}
|
||||
@@ -28,7 +57,10 @@ class AgentAllowController extends Controller
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
//
|
||||
$request->validate($this->getRules());
|
||||
$result = $this->repository->store($request->all());
|
||||
$resource = new AgentAllowResource($result);
|
||||
return $this->success($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,8 +85,8 @@ class AgentAllowController extends Controller
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$result = AgentAllow::query()->findOrFail($id);
|
||||
$result->update($request->all());
|
||||
$request->validate($this->getRules());
|
||||
$result = $this->repository->update($request->all(), $id);
|
||||
$resource = new AgentAllowResource($result);
|
||||
return $this->success($resource);
|
||||
}
|
||||
@@ -67,8 +99,24 @@ class AgentAllowController extends Controller
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
$result = AgentAllow::query()->findOrFail($id);
|
||||
$deleted = $result->delete();
|
||||
return $this->success([$deleted]);
|
||||
$result = $this->repository->delete($id);
|
||||
return $this->success($result);
|
||||
}
|
||||
|
||||
public function all()
|
||||
{
|
||||
$result = AgentAllow::query()->orderBy('id', 'desc')->get();
|
||||
$resource = AgentAllowResource::collection($result);
|
||||
return $this->success($resource);
|
||||
}
|
||||
|
||||
public function check(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'peer_id' => 'required|string',
|
||||
'agent' => 'required|string',
|
||||
]);
|
||||
$result = $this->repository->checkClient($request->peer_id, $request->agent, true);
|
||||
return $this->success($result->toArray(), sprintf("Congratulations! the client is allowed by ID: %s", $result->id));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Http\Resources\AgentDenyResource;
|
||||
use App\Models\AgentDeny;
|
||||
use App\Repositories\AgentDenyRepository;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Validation\Rule;
|
||||
|
||||
class AgentDenyController extends Controller
|
||||
{
|
||||
private $repository;
|
||||
|
||||
public function __construct(AgentDenyRepository $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
private function getRules(): array
|
||||
{
|
||||
return [
|
||||
'family_id' => 'required|numeric',
|
||||
'name' => 'required|string',
|
||||
'peer_id' => 'required|string',
|
||||
'agent' => 'required|string',
|
||||
'comment' => 'required|string',
|
||||
|
||||
];
|
||||
}
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
$result = $this->repository->getList($request->all());
|
||||
$resource = AgentDenyResource::collection($result);
|
||||
return $this->success($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
$request->validate($this->getRules());
|
||||
$result = $this->repository->store($request->all());
|
||||
$resource = new AgentDenyResource($result);
|
||||
return $this->success($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
$result = AgentDeny::query()->findOrFail($id);
|
||||
$resource = new AgentDenyResource($result);
|
||||
return $this->success($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
$request->validate($this->getRules());
|
||||
$result = $this->repository->update($request->all(), $id);
|
||||
$resource = new AgentDenyResource($result);
|
||||
return $this->success($resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
$result = $this->repository->delete($id);
|
||||
return $this->success($result);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -20,7 +20,7 @@ class Kernel extends HttpKernel
|
||||
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
|
||||
\App\Http\Middleware\TrimStrings::class,
|
||||
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
// \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class AgentDenyResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'family_id' => $this->family_id,
|
||||
'agent' => $this->agent,
|
||||
'peer_id' => $this->peer_id,
|
||||
'comment' => $this->comment,
|
||||
'name' => $this->name,
|
||||
'family' => new AgentAllowResource($this->whenLoaded('family'))
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -6,11 +6,24 @@ class AgentAllow extends NexusModel
|
||||
{
|
||||
protected $table = 'agent_allowed_family';
|
||||
|
||||
public $timestamps = true;
|
||||
|
||||
protected $fillable = [
|
||||
'family', 'start_name', 'exception', 'allowhttps', 'comment',
|
||||
'peer_id_pattern', 'peer_id_match_num', 'peer_id_matchtype', 'peer_id_start',
|
||||
'agent_pattern', 'agent_match_num', 'agent_matchtype', 'agent_start',
|
||||
];
|
||||
|
||||
const MATCH_TYPE_DEC = 'dec';
|
||||
const MATCH_TYPE_HEX = 'hex';
|
||||
|
||||
public static $matchTypes = [
|
||||
self::MATCH_TYPE_DEC => 'dec',
|
||||
self::MATCH_TYPE_HEX => 'hex',
|
||||
];
|
||||
|
||||
public function denies(): \Illuminate\Database\Eloquent\Relations\HasMany
|
||||
{
|
||||
return $this->hasMany(AgentDeny::class, 'family_id');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
class AgentDeny extends NexusModel
|
||||
{
|
||||
protected $table = 'agent_allowed_exception';
|
||||
|
||||
protected $fillable = [
|
||||
'family_id', 'name', 'peer_id', 'agent', 'comment'
|
||||
];
|
||||
|
||||
public function family(): \Illuminate\Database\Eloquent\Relations\BelongsTo
|
||||
{
|
||||
return $this->belongsTo(AgentAllow::class, 'family_id');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Exceptions\NexusException;
|
||||
use App\Models\AgentAllow;
|
||||
use App\Models\AgentDeny;
|
||||
|
||||
class AgentAllowRepository extends BaseRepository
|
||||
{
|
||||
public function getList(array $params)
|
||||
{
|
||||
$query = AgentAllow::query();
|
||||
if (!empty($params['family'])) {
|
||||
$query->where('family', 'like', "%{$params['family']}%");
|
||||
}
|
||||
list($sortField, $sortType) = $this->getSortFieldAndType($params);
|
||||
$query->orderBy($sortField, $sortType);
|
||||
return $query->paginate();
|
||||
}
|
||||
|
||||
public function store(array $params)
|
||||
{
|
||||
$this->getPatternMatches($params['peer_id_pattern'], $params['peer_id_start'], $params['peer_id_match_num']);
|
||||
$this->getPatternMatches($params['agent_pattern'], $params['agent_start'], $params['agent_match_num']);
|
||||
$model = AgentAllow::query()->create($params);
|
||||
return $model;
|
||||
}
|
||||
|
||||
public function update(array $params, $id)
|
||||
{
|
||||
$this->getPatternMatches($params['peer_id_pattern'], $params['peer_id_start'], $params['peer_id_match_num']);
|
||||
$this->getPatternMatches($params['agent_pattern'], $params['agent_start'], $params['agent_match_num']);
|
||||
$model = AgentAllow::query()->findOrFail($id);
|
||||
$model->update($params);
|
||||
return $model;
|
||||
}
|
||||
|
||||
public function getDetail($id)
|
||||
{
|
||||
$model = AgentAllow::query()->findOrFail($id);
|
||||
return $model;
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$model = AgentAllow::query()->findOrFail($id);
|
||||
$model->denies()->delete();
|
||||
$result = $model->delete();
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getPatternMatches($pattern, $start, $matchNum)
|
||||
{
|
||||
if (!preg_match($pattern, $start, $matches)) {
|
||||
throw new NexusException(sprintf('pattern: %s can not match start: %s', $pattern, $start));
|
||||
}
|
||||
$matchCount = count($matches) - 1;
|
||||
if ($matchNum > $matchCount) {
|
||||
throw new NexusException("pattern: $pattern match start: $start got matches count: $matchCount, but require $matchNum.");
|
||||
}
|
||||
return array_slice($matches, 1, $matchNum);
|
||||
}
|
||||
|
||||
public function checkClient($peerId, $agent, $debug = false)
|
||||
{
|
||||
//check from high version to low version, if high version allow, stop!
|
||||
$allows = AgentAllow::query()
|
||||
->orderBy('peer_id_start', 'desc')
|
||||
->orderBy('agent_start', 'desc')
|
||||
->get();
|
||||
$agentAllowPassed = null;
|
||||
$versionTooLowStr = '';
|
||||
foreach ($allows as $agentAllow) {
|
||||
$agentAllowId = $agentAllow->id;
|
||||
$isPeerIdAllowed = $isAgentAllowed = $isPeerIdTooLow = $isAgentTooLow = false;
|
||||
//check peer_id
|
||||
if ($agentAllow->peer_id_pattern == '') {
|
||||
$isPeerIdAllowed = true;
|
||||
} else {
|
||||
$pattern = $agentAllow->peer_id_pattern;
|
||||
$start = $agentAllow->peer_id_start;
|
||||
$matchType = $agentAllow->peer_id_matchtype;
|
||||
$matchNum = $agentAllow->peer_id_match_num;
|
||||
try {
|
||||
$peerIdResult = $this->isAllowed($pattern, $start, $matchNum, $matchType, $peerId, $debug);
|
||||
if ($debug) {
|
||||
do_log(
|
||||
"agentAllowId: $agentAllowId, peerIdResult: $peerIdResult, with parameters: "
|
||||
. nexus_json_encode(compact('pattern', 'start', 'matchNum', 'matchType', 'peerId'))
|
||||
);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
do_log("agent allow: {$agentAllow->id} check peer_id error: " . $exception->getMessage(), 'error');
|
||||
throw new NexusException("regular expression err for peer_id: " . $start . ", please ask sysop to fix this");
|
||||
}
|
||||
if ($peerIdResult == 1) {
|
||||
$isPeerIdAllowed = true;
|
||||
}
|
||||
if ($peerIdResult == 2) {
|
||||
$isPeerIdTooLow = true;
|
||||
}
|
||||
}
|
||||
|
||||
//check agent
|
||||
if ($agentAllow->agent_pattern == '') {
|
||||
$isAgentAllowed = true;
|
||||
} else {
|
||||
$pattern = $agentAllow->agent_pattern;
|
||||
$start = $agentAllow->agent_start;
|
||||
$matchType = $agentAllow->agent_matchtype;
|
||||
$matchNum = $agentAllow->agent_match_num;
|
||||
try {
|
||||
$agentResult = $this->isAllowed($pattern, $start, $matchNum, $matchType, $agent, $debug);
|
||||
if ($debug) {
|
||||
do_log(
|
||||
"agentAllowId: $agentAllowId, agentResult: $agentResult, with parameters: "
|
||||
. nexus_json_encode(compact('pattern', 'start', 'matchNum', 'matchType', 'agent'))
|
||||
);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
do_log("agent allow: {$agentAllow->id} check agent error: " . $exception->getMessage(), 'error');
|
||||
throw new NexusException("regular expression err for agent: " . $start . ", please ask sysop to fix this");
|
||||
}
|
||||
if ($agentResult == 1) {
|
||||
$isAgentAllowed = true;
|
||||
}
|
||||
if ($agentResult == 2) {
|
||||
$isAgentTooLow = true;
|
||||
}
|
||||
}
|
||||
|
||||
//both OK, passed, client is allowed
|
||||
if ($isPeerIdAllowed && $isAgentAllowed) {
|
||||
$agentAllowPassed = $agentAllow;
|
||||
break;
|
||||
}
|
||||
if ($isPeerIdTooLow && $isAgentTooLow) {
|
||||
$versionTooLowStr = "Your " . $agentAllow->family . " 's version is too low, please update it after " . $agentAllow->start_name;
|
||||
}
|
||||
}
|
||||
|
||||
if ($versionTooLowStr) {
|
||||
throw new NexusException($versionTooLowStr);
|
||||
}
|
||||
|
||||
if (!$agentAllowPassed) {
|
||||
throw new NexusException("Banned Client, Please goto " . getSchemeAndHttpHost() . "/faq.php#id29 for a list of acceptable clients");
|
||||
}
|
||||
|
||||
if ($debug) {
|
||||
do_log("agentAllowPassed: " . $agentAllowPassed->toJson());
|
||||
}
|
||||
|
||||
// check if exclude
|
||||
if ($agentAllowPassed->exception == 'yes') {
|
||||
$agentDeny = $this->checkIsDenied($peerId, $agent, $agentAllowPassed->id);
|
||||
if ($agentDeny) {
|
||||
if ($debug) {
|
||||
do_log("agentDeny: " . $agentDeny->toJson());
|
||||
}
|
||||
throw new NexusException(sprintf(
|
||||
"[%s-%s]Client: %s is banned due to: %s",
|
||||
$agentAllowPassed->id, $agentDeny->id, $agentDeny->name, $agentDeny->comment
|
||||
));
|
||||
}
|
||||
}
|
||||
if (isHttps() && $agentAllowPassed->allowhttps != 'yes') {
|
||||
throw new NexusException(sprintf(
|
||||
"[%s]This client does not support https well, Please goto %s/faq.php#id29 for a list of proper clients",
|
||||
$agentAllowPassed->id, getSchemeAndHttpHost()
|
||||
));
|
||||
}
|
||||
|
||||
return $agentAllowPassed;
|
||||
|
||||
}
|
||||
|
||||
private function checkIsDenied($peerId, $agent, $familyId)
|
||||
{
|
||||
$agentDenies = AgentDeny::query()->where('family_id', $familyId)->get();
|
||||
foreach ($agentDenies as $agentDeny) {
|
||||
if ($agentDeny->agent == $agent && preg_match("/^" . $agentDeny->peer_id . "/", $peerId)) {
|
||||
return $agentDeny;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check peer_id or agent is allowed
|
||||
*
|
||||
* 0: not allowed
|
||||
* 1: allowed
|
||||
* 2: version too low
|
||||
*
|
||||
* @param $pattern
|
||||
* @param $start
|
||||
* @param $matchNum
|
||||
* @param $matchType
|
||||
* @param $value
|
||||
* @param bool $debug
|
||||
* @return int
|
||||
* @throws NexusException
|
||||
*/
|
||||
private function isAllowed($pattern, $start, $matchNum, $matchType, $value, $debug = false): int
|
||||
{
|
||||
$matchBench = $this->getPatternMatches($pattern, $start, $matchNum);
|
||||
if ($debug) {
|
||||
do_log("matchBench: " . nexus_json_encode($matchBench));
|
||||
}
|
||||
if (!preg_match($pattern, $value, $matchTarget)) {
|
||||
return 0;
|
||||
}
|
||||
if ($matchNum <= 0) {
|
||||
return 1;
|
||||
}
|
||||
$matchTarget = array_slice($matchTarget, 1);
|
||||
if ($debug) {
|
||||
do_log("matchTarget: " . nexus_json_encode($matchTarget));
|
||||
}
|
||||
for ($i = 0; $i < $matchNum; $i++) {
|
||||
if (!isset($matchBench[$i]) || !isset($matchTarget[$i])) {
|
||||
break;
|
||||
}
|
||||
if ($matchType == 'dec') {
|
||||
$matchBench[$i] = intval($matchBench[$i]);
|
||||
$matchTarget[$i] = intval($matchTarget[$i]);
|
||||
} elseif ($matchType == 'hex') {
|
||||
$matchBench[$i] = hexdec($matchBench[$i]);
|
||||
$matchTarget[$i] = hexdec($matchTarget[$i]);
|
||||
} else {
|
||||
throw new NexusException(sprintf("Invalid match type: %s", $matchType));
|
||||
}
|
||||
if ($matchTarget[$i] > $matchBench[$i]) {
|
||||
return 1;
|
||||
} elseif ($matchTarget[$i] < $matchBench[$i]) {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
namespace App\Repositories;
|
||||
|
||||
use App\Models\AgentDeny;
|
||||
|
||||
class AgentDenyRepository extends BaseRepository
|
||||
{
|
||||
public function getList(array $params)
|
||||
{
|
||||
$query = AgentDeny::query()->with(['family']);
|
||||
if (!empty($params['family_id'])) {
|
||||
$query->where('family_id', $params['family_id']);
|
||||
}
|
||||
$query->orderBy('family_id', 'desc');
|
||||
return $query->paginate();
|
||||
}
|
||||
|
||||
public function store(array $params)
|
||||
{
|
||||
$model = AgentDeny::query()->create($params);
|
||||
return $model;
|
||||
}
|
||||
|
||||
public function update(array $params, $id)
|
||||
{
|
||||
$model = AgentDeny::query()->findOrFail($id);
|
||||
$model->update($params);
|
||||
return $model;
|
||||
}
|
||||
|
||||
public function getDetail($id)
|
||||
{
|
||||
$model = AgentDeny::query()->findOrFail($id);
|
||||
return $model;
|
||||
}
|
||||
|
||||
public function delete($id)
|
||||
{
|
||||
$model = AgentDeny::query()->findOrFail($id);
|
||||
$result = $model->delete();
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,15 @@ class UserRepository extends BaseRepository
|
||||
public function getList(array $params)
|
||||
{
|
||||
$query = User::query();
|
||||
if (!empty($params['id'])) {
|
||||
$query->where('id', $params['id']);
|
||||
}
|
||||
if (!empty($params['username'])) {
|
||||
$query->where('username', 'like',"%{$params['username']}%");
|
||||
}
|
||||
if (!empty($params['email'])) {
|
||||
$query->where('email', 'like',"%{$params['email']}%");
|
||||
}
|
||||
list($sortField, $sortType) = $this->getSortFieldAndType($params);
|
||||
$query->orderBy($sortField, $sortType);
|
||||
return $query->paginate();
|
||||
|
||||
Reference in New Issue
Block a user