mirror of
https://github.com/v2board/v2board.git
synced 2025-06-16 22:57:47 +08:00
1.7.0
1.7.0
This commit is contained in:
@ -80,15 +80,14 @@ class CheckCommission extends Command
|
||||
|
||||
public function payHandle($inviteUserId, Order $order)
|
||||
{
|
||||
$level = 3;
|
||||
if ((int)config('v2board.commission_distribution_enable', 0)) {
|
||||
$level = 3;
|
||||
$commissionShareLevels = [
|
||||
0 => (int)config('v2board.commission_distribution_l1'),
|
||||
1 => (int)config('v2board.commission_distribution_l2'),
|
||||
2 => (int)config('v2board.commission_distribution_l3')
|
||||
];
|
||||
} else {
|
||||
$level = 3;
|
||||
$commissionShareLevels = [
|
||||
0 => 100
|
||||
];
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Utils\Helper;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class Test extends Command
|
||||
|
@ -89,16 +89,17 @@ class V2boardInstall extends Command
|
||||
while (!$email) {
|
||||
$email = $this->ask('请输入管理员邮箱?');
|
||||
}
|
||||
$password = '';
|
||||
while (!$password) {
|
||||
$password = $this->ask('请输入管理员密码?');
|
||||
}
|
||||
$password = Helper::guid(false);
|
||||
if (!$this->registerAdmin($email, $password)) {
|
||||
abort(500, '管理员账号注册失败,请重试');
|
||||
}
|
||||
|
||||
$this->info('一切就绪');
|
||||
$this->info('访问 http(s)://你的站点/admin 进入管理面板');
|
||||
$this->info("管理员邮箱:{$email}");
|
||||
$this->info("管理员密码:{$password}");
|
||||
|
||||
$defaultSecurePath = crc32(config('app.key'));
|
||||
$this->info("访问 http(s)://你的站点/{$defaultSecurePath} 进入管理面板,你可以用户中心修改你的密码。");
|
||||
} catch (\Exception $e) {
|
||||
$this->error($e->getMessage());
|
||||
}
|
||||
|
@ -53,10 +53,10 @@ class V2boardStatistics extends Command
|
||||
->whereNotIn('status', [0, 2]);
|
||||
$orderCount = $orderBuilder->count();
|
||||
$orderAmount = $orderBuilder->sum('total_amount');
|
||||
$commissionBuilder = Order::where('created_at', '>=', $startAt)
|
||||
$commissionLogBuilder = CommissionLog::where('created_at', '>=', $startAt)
|
||||
->where('created_at', '<', $endAt);
|
||||
$commissionCount = $commissionBuilder->count();
|
||||
$commissionAmount = $commissionBuilder->sum('actual_commission_balance');
|
||||
$commissionCount = $commissionLogBuilder->count();
|
||||
$commissionAmount = $commissionLogBuilder->sum('get_amount');
|
||||
$data = [
|
||||
'order_count' => $orderCount,
|
||||
'order_amount' => $orderAmount,
|
||||
|
@ -107,7 +107,8 @@ class ConfigController extends Controller
|
||||
'currency_symbol' => config('v2board.currency_symbol', '¥'),
|
||||
'register_limit_by_ip_enable' => (int)config('v2board.register_limit_by_ip_enable', 0),
|
||||
'register_limit_count' => config('v2board.register_limit_count', 3),
|
||||
'register_limit_expire' => config('v2board.register_limit_expire', 60)
|
||||
'register_limit_expire' => config('v2board.register_limit_expire', 60),
|
||||
'secure_path' => config('v2board.secure_path', config('v2board.frontend_admin_path', crc32(config('app.key'))))
|
||||
],
|
||||
'subscribe' => [
|
||||
'plan_change_enable' => (int)config('v2board.plan_change_enable', 1),
|
||||
@ -124,14 +125,11 @@ class ConfigController extends Controller
|
||||
'frontend_theme_header' => config('v2board.frontend_theme_header', 'dark'),
|
||||
'frontend_theme_color' => config('v2board.frontend_theme_color', 'default'),
|
||||
'frontend_background_url' => config('v2board.frontend_background_url'),
|
||||
'frontend_admin_path' => config('v2board.frontend_admin_path', 'admin')
|
||||
],
|
||||
'server' => [
|
||||
'server_token' => config('v2board.server_token'),
|
||||
'server_license' => config('v2board.server_license'),
|
||||
'server_log_enable' => config('v2board.server_log_enable', 0),
|
||||
'server_v2ray_domain' => config('v2board.server_v2ray_domain'),
|
||||
'server_v2ray_protocol' => config('v2board.server_v2ray_protocol'),
|
||||
'server_pull_interval' => config('v2board.server_pull_interval', 60),
|
||||
'server_push_interval' => config('v2board.server_push_interval', 60),
|
||||
],
|
||||
'email' => [
|
||||
'email_template' => config('v2board.email_template', 'default'),
|
||||
|
@ -41,10 +41,13 @@ class PlanController extends Controller
|
||||
DB::beginTransaction();
|
||||
// update user group id and transfer
|
||||
try {
|
||||
User::where('plan_id', $plan->id)->update([
|
||||
'group_id' => $params['group_id'],
|
||||
'transfer_enable' => $params['transfer_enable'] * 1073741824
|
||||
]);
|
||||
if ($request->input('force_update')) {
|
||||
User::where('plan_id', $plan->id)->update([
|
||||
'group_id' => $params['group_id'],
|
||||
'transfer_enable' => $params['transfer_enable'] * 1073741824,
|
||||
'speed_limit' => $params['speed_limit']
|
||||
]);
|
||||
}
|
||||
$plan->update($params);
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
|
57
app/Http/Controllers/Admin/Server/RouteController.php
Normal file
57
app/Http/Controllers/Admin/Server/RouteController.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Admin\Server;
|
||||
|
||||
use App\Http\Requests\Admin\ServerShadowsocksSave;
|
||||
use App\Http\Requests\Admin\ServerShadowsocksUpdate;
|
||||
use App\Models\ServerRoute;
|
||||
use App\Models\ServerShadowsocks;
|
||||
use App\Services\ServerService;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
|
||||
class RouteController extends Controller
|
||||
{
|
||||
public function fetch(Request $request)
|
||||
{
|
||||
$routes = ServerRoute::get();
|
||||
return [
|
||||
'data' => $routes
|
||||
];
|
||||
}
|
||||
|
||||
public function save(Request $request)
|
||||
{
|
||||
$params = $request->validate([
|
||||
'remarks' => 'required',
|
||||
'match' => 'required',
|
||||
'action' => 'required',
|
||||
'action_value' => 'nullable'
|
||||
]);
|
||||
if ($request->input('id')) {
|
||||
try {
|
||||
$route = ServerRoute::find($request->input('id'));
|
||||
$route->update($params);
|
||||
return [
|
||||
'data' => true
|
||||
];
|
||||
} catch (\Exception $e) {
|
||||
abort(500, '保存失败');
|
||||
}
|
||||
}
|
||||
if (!ServerRoute::create($params)) abort(500, '创建失败');
|
||||
return [
|
||||
'data' => true
|
||||
];
|
||||
}
|
||||
|
||||
public function drop(Request $request)
|
||||
{
|
||||
$route = ServerRoute::find($request->input('id'));
|
||||
if (!$route) abort(500, '路由不存在');
|
||||
if (!$route->delete()) abort(500, '删除失败');
|
||||
return [
|
||||
'data' => true
|
||||
];
|
||||
}
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Models\CommissionLog;
|
||||
use App\Models\ServerShadowsocks;
|
||||
use App\Models\ServerTrojan;
|
||||
use App\Models\StatUser;
|
||||
@ -47,14 +48,12 @@ class StatController extends Controller
|
||||
->where('created_at', '<', strtotime(date('Y-m-1')))
|
||||
->whereNotIn('status', [0, 2])
|
||||
->sum('total_amount'),
|
||||
'commission_month_payout' => Order::where('actual_commission_balance' ,'!=', NULL)
|
||||
->where('created_at', '>=', strtotime(date('Y-m-1')))
|
||||
'commission_month_payout' => CommissionLog::where('created_at', '>=', strtotime(date('Y-m-1')))
|
||||
->where('created_at', '<', time())
|
||||
->sum('actual_commission_balance'),
|
||||
'commission_last_month_payout' => Order::where('actual_commission_balance' ,'!=', NULL)
|
||||
->where('created_at', '>=', strtotime('-1 month', strtotime(date('Y-m-1'))))
|
||||
->sum('get_amount'),
|
||||
'commission_last_month_payout' => CommissionLog::where('created_at', '>=', strtotime('-1 month', strtotime(date('Y-m-1'))))
|
||||
->where('created_at', '<', strtotime(date('Y-m-1')))
|
||||
->sum('actual_commission_balance'),
|
||||
->sum('get_amount'),
|
||||
]
|
||||
]);
|
||||
}
|
||||
@ -100,7 +99,7 @@ class StatController extends Controller
|
||||
{
|
||||
$servers = [
|
||||
'shadowsocks' => ServerShadowsocks::where('parent_id', null)->get()->toArray(),
|
||||
'vmess' => ServerV2ray::where('parent_id', null)->get()->toArray(),
|
||||
'v2ray' => ServerV2ray::where('parent_id', null)->get()->toArray(),
|
||||
'trojan' => ServerTrojan::where('parent_id', null)->get()->toArray()
|
||||
];
|
||||
$startAt = strtotime('-1 day', strtotime(date('Y-m-d')));
|
||||
|
@ -33,7 +33,14 @@ class AppController extends Controller
|
||||
$proxies = [];
|
||||
|
||||
foreach ($servers as $item) {
|
||||
if ($item['type'] === 'shadowsocks') {
|
||||
if ($item['type'] === 'shadowsocks'
|
||||
&& in_array($item['cipher'], [
|
||||
'aes-128-gcm',
|
||||
'aes-192-gcm',
|
||||
'aes-256-gcm',
|
||||
'chacha20-ietf-poly1305'
|
||||
])
|
||||
) {
|
||||
array_push($proxy, Protocols\Clash::buildShadowsocks($user['uuid'], $item));
|
||||
array_push($proxies, $item['name']);
|
||||
}
|
||||
|
@ -13,9 +13,7 @@ class ClientController extends Controller
|
||||
public function subscribe(Request $request)
|
||||
{
|
||||
$flag = $request->input('flag')
|
||||
?? (isset($_SERVER['HTTP_USER_AGENT'])
|
||||
? $_SERVER['HTTP_USER_AGENT']
|
||||
: '');
|
||||
?? ($_SERVER['HTTP_USER_AGENT'] ?? '');
|
||||
$flag = strtolower($flag);
|
||||
$user = $request->user;
|
||||
// account not expired and is not banned.
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers\Client\Protocols;
|
||||
|
||||
use App\Utils\Dict;
|
||||
use phpDocumentor\Reflection\Types\Self_;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
|
||||
class Clash
|
||||
@ -36,7 +38,14 @@ class Clash
|
||||
$proxies = [];
|
||||
|
||||
foreach ($servers as $item) {
|
||||
if ($item['type'] === 'shadowsocks') {
|
||||
if ($item['type'] === 'shadowsocks'
|
||||
&& in_array($item['cipher'], [
|
||||
'aes-128-gcm',
|
||||
'aes-192-gcm',
|
||||
'aes-256-gcm',
|
||||
'chacha20-ietf-poly1305'
|
||||
])
|
||||
) {
|
||||
array_push($proxy, self::buildShadowsocks($user['uuid'], $item));
|
||||
array_push($proxies, $item['name']);
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace App\Http\Controllers\Client\Protocols;
|
||||
|
||||
use App\Utils\Helper;
|
||||
|
||||
class Shadowrocket
|
||||
{
|
||||
public $flag = 'shadowrocket';
|
||||
@ -43,6 +45,16 @@ class Shadowrocket
|
||||
|
||||
public static function buildShadowsocks($password, $server)
|
||||
{
|
||||
if ($server['cipher'] === '2022-blake3-aes-128-gcm') {
|
||||
$serverKey = Helper::getShadowsocksServerKey($server['created_at'], 16);
|
||||
$userKey = Helper::uuidToBase64($password, 16);
|
||||
$password = "{$serverKey}:{$userKey}";
|
||||
}
|
||||
if ($server['cipher'] === '2022-blake3-aes-256-gcm') {
|
||||
$serverKey = Helper::getShadowsocksServerKey($server['created_at'], 32);
|
||||
$userKey = Helper::uuidToBase64($password, 32);
|
||||
$password = "{$serverKey}:{$userKey}";
|
||||
}
|
||||
$name = rawurlencode($server['name']);
|
||||
$str = str_replace(
|
||||
['+', '/', '='],
|
||||
|
@ -29,7 +29,9 @@ class Shadowsocks
|
||||
$bytesRemaining = $user['transfer_enable'] - $bytesUsed;
|
||||
|
||||
foreach ($servers as $item) {
|
||||
if ($item['type'] === 'shadowsocks') {
|
||||
if ($item['type'] === 'shadowsocks'
|
||||
&& in_array($item['cipher'], ['aes-128-gcm', 'aes-256-gcm', 'aes-192-gcm'])
|
||||
) {
|
||||
array_push($configs, self::SIP008($item, $user));
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,14 @@ class Stash
|
||||
$proxies = [];
|
||||
|
||||
foreach ($servers as $item) {
|
||||
if ($item['type'] === 'shadowsocks') {
|
||||
if ($item['type'] === 'shadowsocks'
|
||||
&& in_array($item['cipher'], [
|
||||
'aes-128-gcm',
|
||||
'aes-192-gcm',
|
||||
'aes-256-gcm',
|
||||
'chacha20-ietf-poly1305'
|
||||
])
|
||||
) {
|
||||
array_push($proxy, self::buildShadowsocks($user['uuid'], $item));
|
||||
array_push($proxies, $item['name']);
|
||||
}
|
||||
|
@ -28,7 +28,14 @@ class Surfboard
|
||||
$proxyGroup = '';
|
||||
|
||||
foreach ($servers as $item) {
|
||||
if ($item['type'] === 'shadowsocks') {
|
||||
if ($item['type'] === 'shadowsocks'
|
||||
&& in_array($item['cipher'], [
|
||||
'aes-128-gcm',
|
||||
'aes-192-gcm',
|
||||
'aes-256-gcm',
|
||||
'chacha20-ietf-poly1305'
|
||||
])
|
||||
) {
|
||||
// [Proxy]
|
||||
$proxies .= self::buildShadowsocks($user['uuid'], $item);
|
||||
// [Proxy Group]
|
||||
|
@ -28,7 +28,14 @@ class Surge
|
||||
$proxyGroup = '';
|
||||
|
||||
foreach ($servers as $item) {
|
||||
if ($item['type'] === 'shadowsocks') {
|
||||
if ($item['type'] === 'shadowsocks'
|
||||
&& in_array($item['cipher'], [
|
||||
'aes-128-gcm',
|
||||
'aes-192-gcm',
|
||||
'aes-256-gcm',
|
||||
'chacha20-ietf-poly1305'
|
||||
])
|
||||
) {
|
||||
// [Proxy]
|
||||
$proxies .= self::buildShadowsocks($user['uuid'], $item);
|
||||
// [Proxy Group]
|
||||
|
@ -23,6 +23,19 @@ class CommController extends Controller
|
||||
'app_description' => config('v2board.app_description'),
|
||||
'app_url' => config('v2board.app_url'),
|
||||
'logo' => config('v2board.logo'),
|
||||
|
||||
// TODO:REMOVE:1.7.0
|
||||
|
||||
'tosUrl' => config('v2board.tos_url'),
|
||||
'isEmailVerify' => (int)config('v2board.email_verify', 0) ? 1 : 0,
|
||||
'isInviteForce' => (int)config('v2board.invite_force', 0) ? 1 : 0,
|
||||
'emailWhitelistSuffix' => (int)config('v2board.email_whitelist_enable', 0)
|
||||
? $this->getEmailSuffix()
|
||||
: 0,
|
||||
'isRecaptcha' => (int)config('v2board.recaptcha_enable', 0) ? 1 : 0,
|
||||
'recaptchaSiteKey' => config('v2board.recaptcha_site_key'),
|
||||
'appDescription' => config('v2board.app_description'),
|
||||
'appUrl' => config('v2board.app_url'),
|
||||
]
|
||||
]);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ use App\Http\Requests\Passport\AuthRegister;
|
||||
use App\Http\Requests\Passport\AuthForget;
|
||||
use App\Http\Requests\Passport\AuthLogin;
|
||||
use App\Jobs\SendEmailJob;
|
||||
use App\Services\AuthService;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use App\Models\Plan;
|
||||
@ -16,6 +17,7 @@ use App\Utils\Helper;
|
||||
use App\Utils\Dict;
|
||||
use App\Utils\CacheKey;
|
||||
use ReCaptcha\ReCaptcha;
|
||||
use Firebase\JWT\JWT;
|
||||
|
||||
class AuthController extends Controller
|
||||
{
|
||||
@ -77,7 +79,9 @@ class AuthController extends Controller
|
||||
if ((int)config('v2board.register_limit_by_ip_enable', 0)) {
|
||||
$registerCountByIP = Cache::get(CacheKey::get('REGISTER_IP_RATE_LIMIT', $request->ip())) ?? 0;
|
||||
if ((int)$registerCountByIP >= (int)config('v2board.register_limit_count', 3)) {
|
||||
abort(500, __('Register frequently, please try again after 1 hour'));
|
||||
abort(500, __('Register frequently, please try again after :minute minute', [
|
||||
'minute' => config('v2board.register_limit_expire', 60)
|
||||
]));
|
||||
}
|
||||
}
|
||||
if ((int)config('v2board.recaptcha_enable', 0)) {
|
||||
@ -163,11 +167,6 @@ class AuthController extends Controller
|
||||
Cache::forget(CacheKey::get('EMAIL_VERIFY_CODE', $request->input('email')));
|
||||
}
|
||||
|
||||
$data = [
|
||||
'token' => $user->token,
|
||||
'auth_data' => base64_encode("{$user->email}:{$user->password}")
|
||||
];
|
||||
|
||||
$user->last_login_at = time();
|
||||
$user->save();
|
||||
|
||||
@ -178,8 +177,11 @@ class AuthController extends Controller
|
||||
(int)config('v2board.register_limit_expire', 60) * 60
|
||||
);
|
||||
}
|
||||
|
||||
$authService = new AuthService($user);
|
||||
|
||||
return response()->json([
|
||||
'data' => $data
|
||||
'data' => $authService->generateAuthData('register')
|
||||
]);
|
||||
}
|
||||
|
||||
@ -188,6 +190,12 @@ class AuthController extends Controller
|
||||
$email = $request->input('email');
|
||||
$password = $request->input('password');
|
||||
|
||||
$passwordErrorCount = (int)Cache::get(CacheKey::get('PASSWORD_ERROR_LIMIT', $email), 0);
|
||||
|
||||
if ($passwordErrorCount >= 5) {
|
||||
abort(500, __('There are too many password errors, please try again after 30 minutes.'));
|
||||
}
|
||||
|
||||
$user = User::where('email', $email)->first();
|
||||
if (!$user) {
|
||||
abort(500, __('Incorrect email or password'));
|
||||
@ -198,6 +206,11 @@ class AuthController extends Controller
|
||||
$password,
|
||||
$user->password)
|
||||
) {
|
||||
Cache::put(
|
||||
CacheKey::get('PASSWORD_ERROR_LIMIT', $email),
|
||||
(int)$passwordErrorCount + 1,
|
||||
30 * 60
|
||||
);
|
||||
abort(500, __('Incorrect email or password'));
|
||||
}
|
||||
|
||||
@ -205,14 +218,9 @@ class AuthController extends Controller
|
||||
abort(500, __('Your account has been suspended'));
|
||||
}
|
||||
|
||||
$data = [
|
||||
'token' => $user->token,
|
||||
'auth_data' => base64_encode("{$user->email}:{$user->password}")
|
||||
];
|
||||
|
||||
if ($user->is_admin) $data['is_admin'] = true;
|
||||
$authService = new AuthService($user);
|
||||
return response([
|
||||
'data' => $data
|
||||
'data' => $authService->generateAuthData('login')
|
||||
]);
|
||||
}
|
||||
|
||||
@ -241,49 +249,25 @@ class AuthController extends Controller
|
||||
if ($user->banned) {
|
||||
abort(500, __('Your account has been suspended'));
|
||||
}
|
||||
$data = [
|
||||
'token' => $user->token,
|
||||
'auth_data' => base64_encode("{$user->email}:{$user->password}")
|
||||
];
|
||||
Cache::forget($key);
|
||||
$authService = new AuthService($user);
|
||||
return response([
|
||||
'data' => $data
|
||||
'data' => $authService->generateAuthData('token')
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public function getTempToken(Request $request)
|
||||
{
|
||||
$user = User::where('token', $request->input('token'))->first();
|
||||
if (!$user) {
|
||||
abort(500, __('Token error'));
|
||||
}
|
||||
|
||||
$code = Helper::guid();
|
||||
$key = CacheKey::get('TEMP_TOKEN', $code);
|
||||
Cache::put($key, $user->id, 60);
|
||||
return response([
|
||||
'data' => $code
|
||||
]);
|
||||
}
|
||||
|
||||
public function getQuickLoginUrl(Request $request)
|
||||
{
|
||||
$authorization = $request->input('auth_data') ?? $request->header('authorization');
|
||||
if (!$authorization) abort(403, '未登录或登陆已过期');
|
||||
|
||||
$authData = explode(':', base64_decode($authorization));
|
||||
if (!isset($authData[0]) || !isset($authData[1])) abort(403, __('Token error'));
|
||||
$user = User::where('email', $authData[0])
|
||||
->where('password', $authData[1])
|
||||
->first();
|
||||
if (!$user) {
|
||||
abort(500, __('Token error'));
|
||||
}
|
||||
$user = AuthService::decryptAuthData($authorization);
|
||||
if (!$user) abort(403, '未登录或登陆已过期');
|
||||
|
||||
$code = Helper::guid();
|
||||
$key = CacheKey::get('TEMP_TOKEN', $code);
|
||||
Cache::put($key, $user->id, 60);
|
||||
Cache::put($key, $user['id'], 60);
|
||||
$redirect = '/#/login?verify=' . $code . '&redirect=' . ($request->input('redirect') ? $request->input('redirect') : 'dashboard');
|
||||
if (config('v2board.app_url')) {
|
||||
$url = config('v2board.app_url') . $redirect;
|
||||
|
@ -84,7 +84,7 @@ class DeepbworkController extends Controller
|
||||
foreach ($data as $item) {
|
||||
$u = $item['u'];
|
||||
$d = $item['d'];
|
||||
$userService->trafficFetch($u, $d, $item['user_id'], $server->toArray(), 'vmess');
|
||||
$userService->trafficFetch($u, $d, $item['user_id'], $server->toArray(), 'v2ray');
|
||||
}
|
||||
|
||||
return response([
|
||||
|
@ -5,6 +5,7 @@ namespace App\Http\Controllers\Server;
|
||||
use App\Services\ServerService;
|
||||
use App\Services\UserService;
|
||||
use App\Utils\CacheKey;
|
||||
use App\Utils\Helper;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\ServerShadowsocks;
|
||||
@ -12,12 +13,12 @@ use App\Models\ServerV2ray;
|
||||
use App\Models\ServerTrojan;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class VProxyController extends Controller
|
||||
class UniProxyController extends Controller
|
||||
{
|
||||
private $nodeType;
|
||||
private $nodeInfo;
|
||||
private $nodeId;
|
||||
private $token;
|
||||
private $serverService;
|
||||
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
@ -28,25 +29,11 @@ class VProxyController extends Controller
|
||||
if ($token !== config('v2board.server_token')) {
|
||||
abort(500, 'token is error');
|
||||
}
|
||||
$this->token = $token;
|
||||
$this->nodeType = $request->input('node_type');
|
||||
$this->nodeId = $request->input('node_id');
|
||||
switch ($this->nodeType) {
|
||||
case 'v2ray':
|
||||
$this->nodeInfo = ServerV2ray::find($this->nodeId);
|
||||
break;
|
||||
case 'shadowsocks':
|
||||
$this->nodeInfo = ServerShadowsocks::find($this->nodeId);
|
||||
break;
|
||||
case 'trojan':
|
||||
$this->nodeInfo = ServerTrojan::find($this->nodeId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (!$this->nodeInfo) {
|
||||
abort(500, 'server not found');
|
||||
}
|
||||
$this->serverService = new ServerService();
|
||||
$this->nodeInfo = $this->serverService->getServer($this->nodeId, $this->nodeType);
|
||||
if (!$this->nodeInfo) abort(500, 'server is not exist');
|
||||
}
|
||||
|
||||
// 后端获取用户
|
||||
@ -54,21 +41,11 @@ class VProxyController extends Controller
|
||||
{
|
||||
ini_set('memory_limit', -1);
|
||||
Cache::put(CacheKey::get('SERVER_' . strtoupper($this->nodeType) . '_LAST_CHECK_AT', $this->nodeInfo->id), time(), 3600);
|
||||
$serverService = new ServerService();
|
||||
$users = $serverService->getAvailableUsers($this->nodeInfo->group_id);
|
||||
$users = $this->serverService->getAvailableUsers($this->nodeInfo->group_id);
|
||||
$users = $users->toArray();
|
||||
|
||||
$response['users'] = $users;
|
||||
|
||||
switch ($this->nodeType) {
|
||||
case 'shadowsocks':
|
||||
$response['server'] = [
|
||||
'cipher' => $this->nodeInfo->cipher,
|
||||
'server_port' => $this->nodeInfo->server_port
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
$eTag = sha1(json_encode($response));
|
||||
if (strpos($request->header('If-None-Match'), $eTag) !== false ) {
|
||||
abort(304);
|
||||
@ -78,17 +55,17 @@ class VProxyController extends Controller
|
||||
}
|
||||
|
||||
// 后端提交数据
|
||||
public function submit(Request $request)
|
||||
public function push(Request $request)
|
||||
{
|
||||
$data = file_get_contents('php://input');
|
||||
$data = json_decode($data, true);
|
||||
Cache::put(CacheKey::get('SERVER_' . strtoupper($this->nodeType) . '_ONLINE_USER', $this->nodeInfo->id), count($data), 3600);
|
||||
Cache::put(CacheKey::get('SERVER_' . strtoupper($this->nodeType) . '_LAST_PUSH_AT', $this->nodeInfo->id), time(), 3600);
|
||||
$userService = new UserService();
|
||||
foreach ($data as $item) {
|
||||
$u = $item['u'];
|
||||
$d = $item['d'];
|
||||
$userService->trafficFetch($u, $d, $item['user_id'], $this->nodeInfo->toArray(), $this->nodeType);
|
||||
foreach (array_keys($data) as $k) {
|
||||
$u = $data[$k][0];
|
||||
$d = $data[$k][1];
|
||||
$userService->trafficFetch($u, $d, $k, $this->nodeInfo->toArray(), $this->nodeType);
|
||||
}
|
||||
|
||||
return response([
|
||||
@ -101,28 +78,48 @@ class VProxyController extends Controller
|
||||
{
|
||||
switch ($this->nodeType) {
|
||||
case 'shadowsocks':
|
||||
die(json_encode([
|
||||
$response = [
|
||||
'server_port' => $this->nodeInfo->server_port,
|
||||
'cipher' => $this->nodeInfo->cipher,
|
||||
'obfs' => $this->nodeInfo->obfs,
|
||||
'obfs_settings' => $this->nodeInfo->obfs_settings
|
||||
], JSON_UNESCAPED_UNICODE));
|
||||
];
|
||||
|
||||
if ($this->nodeInfo->cipher === '2022-blake3-aes-128-gcm') {
|
||||
$response['server_key'] = Helper::getShadowsocksServerKey($this->nodeInfo->created_at, 16);
|
||||
}
|
||||
if ($this->nodeInfo->cipher === '2022-blake3-aes-256-gcm') {
|
||||
$response['server_key'] = Helper::getShadowsocksServerKey($this->nodeInfo->created_at, 32);
|
||||
}
|
||||
break;
|
||||
case 'v2ray':
|
||||
die(json_encode([
|
||||
$response = [
|
||||
'server_port' => $this->nodeInfo->server_port,
|
||||
'network' => $this->nodeInfo->network,
|
||||
'cipher' => $this->nodeInfo->cipher,
|
||||
'networkSettings' => $this->nodeInfo->networkSettings,
|
||||
'tls' => $this->nodeInfo->tls
|
||||
], JSON_UNESCAPED_UNICODE));
|
||||
];
|
||||
break;
|
||||
case 'trojan':
|
||||
die(json_encode([
|
||||
$response = [
|
||||
'host' => $this->nodeInfo->host,
|
||||
'server_port' => $this->nodeInfo->server_port
|
||||
], JSON_UNESCAPED_UNICODE));
|
||||
'server_port' => $this->nodeInfo->server_port,
|
||||
'server_name' => $this->nodeInfo->server_name
|
||||
];
|
||||
break;
|
||||
}
|
||||
$response['base_config'] = [
|
||||
'push_interval' => config('v2board.server_push_interval', 60),
|
||||
'pull_interval' => config('v2board.server_pull_interval', 60)
|
||||
];
|
||||
if ($this->nodeInfo['route_id']) {
|
||||
$response['routes'] = $this->serverService->getRoutes($this->nodeInfo['route_id']);
|
||||
}
|
||||
$eTag = sha1(json_encode($response));
|
||||
if (strpos($request->header('If-None-Match'), $eTag) !== false ) {
|
||||
abort(304);
|
||||
}
|
||||
|
||||
return response($response)->header('ETag', "\"{$eTag}\"");
|
||||
}
|
||||
}
|
@ -58,19 +58,21 @@ class InviteController extends Controller
|
||||
if ($user->commission_rate) {
|
||||
$commission_rate = $user->commission_rate;
|
||||
}
|
||||
$uncheck_commission_balance = (int)Order::where('status', 3)
|
||||
->where('commission_status', 0)
|
||||
->where('invite_user_id', $request->user['id'])
|
||||
->sum('commission_balance');
|
||||
if (config('v2board.commission_distribution_enable', 0)) {
|
||||
$uncheck_commission_balance = $uncheck_commission_balance * (config('v2board.commission_distribution_l1') / 100);
|
||||
}
|
||||
$stat = [
|
||||
//已注册用户数
|
||||
(int)User::where('invite_user_id', $request->user['id'])->count(),
|
||||
//有效的佣金
|
||||
(int)Order::where('status', 3)
|
||||
->where('commission_status', 2)
|
||||
->where('invite_user_id', $request->user['id'])
|
||||
->sum('commission_balance'),
|
||||
(int)CommissionLog::where('invite_user_id', $request->user['id'])
|
||||
->sum('get_amount'),
|
||||
//确认中的佣金
|
||||
(int)Order::where('status', 3)
|
||||
->where('commission_status', 0)
|
||||
->where('invite_user_id', $request->user['id'])
|
||||
->sum('commission_balance'),
|
||||
$uncheck_commission_balance,
|
||||
//佣金比例
|
||||
(int)$commission_rate,
|
||||
//可用佣金
|
||||
|
@ -85,7 +85,7 @@ class OrderController extends Controller
|
||||
abort(500, __('Subscription plan does not exist'));
|
||||
}
|
||||
|
||||
if (!$planService->haveCapacity() && $request->input('period') !== 'reset_price') {
|
||||
if ($user->plan_id !== $plan->id && !$planService->haveCapacity() && $request->input('period') !== 'reset_price') {
|
||||
abort(500, __('Current product is sold out'));
|
||||
}
|
||||
|
||||
|
@ -26,8 +26,14 @@ class ServerController extends Controller
|
||||
$serverService = new ServerService();
|
||||
$servers = $serverService->getAvailableServers($user);
|
||||
}
|
||||
|
||||
$eTag = sha1(json_encode(array_column($servers, 'updated_at')));
|
||||
if (strpos($request->header('If-None-Match'), $eTag) !== false ) {
|
||||
abort(304);
|
||||
}
|
||||
|
||||
return response([
|
||||
'data' => $servers
|
||||
]);
|
||||
])->header('ETag', "\"{$eTag}\"");
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +113,8 @@ class UserController extends Controller
|
||||
'u',
|
||||
'd',
|
||||
'transfer_enable',
|
||||
'email'
|
||||
'email',
|
||||
'uuid'
|
||||
])
|
||||
->first();
|
||||
if (!$user) {
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Services\AuthService;
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
@ -19,24 +20,10 @@ class Admin
|
||||
$authorization = $request->input('auth_data') ?? $request->header('authorization');
|
||||
if (!$authorization) abort(403, '未登录或登陆已过期');
|
||||
|
||||
$authData = explode(':', base64_decode($authorization));
|
||||
if (!Cache::has($authorization)) {
|
||||
if (!isset($authData[1]) || !isset($authData[0])) abort(403, '鉴权失败,请重新登入');
|
||||
$user = \App\Models\User::where('password', $authData[1])
|
||||
->where('email', $authData[0])
|
||||
->select([
|
||||
'id',
|
||||
'email',
|
||||
'is_admin',
|
||||
'is_staff'
|
||||
])
|
||||
->first();
|
||||
if (!$user) abort(403, '鉴权失败,请重新登入');
|
||||
if (!$user->is_admin) abort(403, '鉴权失败,请重新登入');
|
||||
Cache::put($authorization, $user->toArray(), 3600);
|
||||
}
|
||||
$user = AuthService::decryptAuthData($authorization);
|
||||
if (!$user || !$user['is_admin']) abort(403, '未登录或登陆已过期');
|
||||
$request->merge([
|
||||
'user' => Cache::get($authorization)
|
||||
'user' => $user
|
||||
]);
|
||||
return $next($request);
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Services\AuthService;
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class Staff
|
||||
{
|
||||
@ -19,24 +19,10 @@ class Staff
|
||||
$authorization = $request->input('auth_data') ?? $request->header('authorization');
|
||||
if (!$authorization) abort(403, '未登录或登陆已过期');
|
||||
|
||||
$authData = explode(':', base64_decode($authorization));
|
||||
if (!Cache::has($authorization)) {
|
||||
if (!isset($authData[1]) || !isset($authData[0])) abort(403, '鉴权失败,请重新登入');
|
||||
$user = \App\Models\User::where('password', $authData[1])
|
||||
->where('email', $authData[0])
|
||||
->select([
|
||||
'id',
|
||||
'email',
|
||||
'is_admin',
|
||||
'is_staff'
|
||||
])
|
||||
->first();
|
||||
if (!$user) abort(403, '鉴权失败,请重新登入');
|
||||
if (!$user->is_staff) abort(403, '鉴权失败,请重新登入');
|
||||
Cache::put($authorization, $user->toArray(), 3600);
|
||||
}
|
||||
$user = AuthService::decryptAuthData($authorization);
|
||||
if (!$user || !$user['is_staff']) abort(403, '未登录或登陆已过期');
|
||||
$request->merge([
|
||||
'user' => Cache::get($authorization)
|
||||
'user' => $user
|
||||
]);
|
||||
return $next($request);
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Http\Middleware;
|
||||
|
||||
use App\Services\AuthService;
|
||||
use Closure;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
@ -19,23 +20,10 @@ class User
|
||||
$authorization = $request->input('auth_data') ?? $request->header('authorization');
|
||||
if (!$authorization) abort(403, '未登录或登陆已过期');
|
||||
|
||||
$authData = explode(':', base64_decode($authorization));
|
||||
if (!Cache::has($authorization)) {
|
||||
if (!isset($authData[1]) || !isset($authData[0])) abort(403, '鉴权失败,请重新登入');
|
||||
$user = \App\Models\User::where('password', $authData[1])
|
||||
->where('email', $authData[0])
|
||||
->select([
|
||||
'id',
|
||||
'email',
|
||||
'is_admin',
|
||||
'is_staff'
|
||||
])
|
||||
->first();
|
||||
if (!$user) abort(403, '鉴权失败,请重新登入');
|
||||
Cache::put($authorization, $user->toArray(), 3600);
|
||||
}
|
||||
$user = AuthService::decryptAuthData($authorization);
|
||||
if (!$user) abort(403, '未登录或登陆已过期');
|
||||
$request->merge([
|
||||
'user' => Cache::get($authorization)
|
||||
'user' => $user
|
||||
]);
|
||||
return $next($request);
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ class ConfigSave extends FormRequest
|
||||
'register_limit_by_ip_enable' => 'in:0,1',
|
||||
'register_limit_count' => 'integer',
|
||||
'register_limit_expire' => 'integer',
|
||||
'secure_path' => '',
|
||||
// subscribe
|
||||
'plan_change_enable' => 'in:0,1',
|
||||
'reset_traffic_method' => 'in:0,1,2,3,4',
|
||||
@ -56,17 +57,14 @@ class ConfigSave extends FormRequest
|
||||
'show_info_to_server_enable' => 'in:0,1',
|
||||
// server
|
||||
'server_token' => 'nullable|min:16',
|
||||
'server_license' => 'nullable',
|
||||
'server_log_enable' => 'in:0,1',
|
||||
'server_v2ray_domain' => '',
|
||||
'server_v2ray_protocol' => '',
|
||||
'server_pull_interval' => 'integer',
|
||||
'server_push_interval' => 'integer',
|
||||
// frontend
|
||||
'frontend_theme' => '',
|
||||
'frontend_theme_sidebar' => 'in:dark,light',
|
||||
'frontend_theme_header' => 'in:dark,light',
|
||||
'frontend_theme_color' => 'in:default,darkblue,black,green',
|
||||
'frontend_theme_sidebar' => 'nullable|in:dark,light',
|
||||
'frontend_theme_header' => 'nullable|in:dark,light',
|
||||
'frontend_theme_color' => 'nullable|in:default,darkblue,black,green',
|
||||
'frontend_background_url' => 'nullable|url',
|
||||
'frontend_admin_path' => '',
|
||||
// email
|
||||
'email_template' => '',
|
||||
'email_host' => '',
|
||||
|
@ -27,7 +27,8 @@ class PlanSave extends FormRequest
|
||||
'onetime_price' => 'nullable|integer',
|
||||
'reset_price' => 'nullable|integer',
|
||||
'reset_traffic_method' => 'nullable|integer|in:0,1,2,3,4',
|
||||
'capacity_limit' => 'nullable|integer'
|
||||
'capacity_limit' => 'nullable|integer',
|
||||
'speed_limit' => 'nullable|integer'
|
||||
];
|
||||
}
|
||||
|
||||
@ -49,7 +50,8 @@ class PlanSave extends FormRequest
|
||||
'reset_price.integer' => '流量重置包金额有误',
|
||||
'reset_traffic_method.integer' => '流量重置方式格式有误',
|
||||
'reset_traffic_method.in' => '流量重置方式格式有误',
|
||||
'capacity_limit.integer' => '容纳用户量限制格式有误'
|
||||
'capacity_limit.integer' => '容纳用户量限制格式有误',
|
||||
'speed_limit.integer' => '限速格式有误'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -18,10 +18,11 @@ class ServerShadowsocksSave extends FormRequest
|
||||
'name' => 'required',
|
||||
'group_id' => 'required|array',
|
||||
'parent_id' => 'nullable|integer',
|
||||
'route_id' => 'nullable|array',
|
||||
'host' => 'required',
|
||||
'port' => 'required',
|
||||
'server_port' => 'required',
|
||||
'cipher' => 'required|in:aes-128-gcm,aes-256-gcm,chacha20-ietf-poly1305',
|
||||
'cipher' => 'required|in:aes-128-gcm,aes-192-gcm,aes-256-gcm,chacha20-ietf-poly1305,2022-blake3-aes-128-gcm,2022-blake3-aes-256-gcm',
|
||||
'obfs' => 'nullable|in:http',
|
||||
'obfs_settings' => 'nullable|array',
|
||||
'tags' => 'nullable|array',
|
||||
@ -35,6 +36,7 @@ class ServerShadowsocksSave extends FormRequest
|
||||
'name.required' => '节点名称不能为空',
|
||||
'group_id.required' => '权限组不能为空',
|
||||
'group_id.array' => '权限组格式不正确',
|
||||
'route_id.array' => '路由组格式不正确',
|
||||
'parent_id.integer' => '父节点格式不正确',
|
||||
'host.required' => '节点地址不能为空',
|
||||
'port.required' => '连接端口不能为空',
|
||||
|
@ -17,6 +17,7 @@ class ServerTrojanSave extends FormRequest
|
||||
'show' => '',
|
||||
'name' => 'required',
|
||||
'group_id' => 'required|array',
|
||||
'route_id' => 'nullable|array',
|
||||
'parent_id' => 'nullable|integer',
|
||||
'host' => 'required',
|
||||
'port' => 'required',
|
||||
@ -34,6 +35,7 @@ class ServerTrojanSave extends FormRequest
|
||||
'name.required' => '节点名称不能为空',
|
||||
'group_id.required' => '权限组不能为空',
|
||||
'group_id.array' => '权限组格式不正确',
|
||||
'route_id.array' => '路由组格式不正确',
|
||||
'parent_id.integer' => '父节点格式不正确',
|
||||
'host.required' => '节点地址不能为空',
|
||||
'port.required' => '连接端口不能为空',
|
||||
|
@ -17,6 +17,7 @@ class ServerV2raySave extends FormRequest
|
||||
'show' => '',
|
||||
'name' => 'required',
|
||||
'group_id' => 'required|array',
|
||||
'route_id' => 'nullable|array',
|
||||
'parent_id' => 'nullable|integer',
|
||||
'host' => 'required',
|
||||
'port' => 'required',
|
||||
@ -38,6 +39,7 @@ class ServerV2raySave extends FormRequest
|
||||
'name.required' => '节点名称不能为空',
|
||||
'group_id.required' => '权限组不能为空',
|
||||
'group_id.array' => '权限组格式不正确',
|
||||
'route_id.array' => '路由组格式不正确',
|
||||
'parent_id.integer' => '父ID格式不正确',
|
||||
'host.required' => '节点地址不能为空',
|
||||
'port.required' => '连接端口不能为空',
|
||||
|
@ -14,7 +14,7 @@ class UserFetch extends FormRequest
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'filter.*.key' => 'required|in:id,email,transfer_enable,d,expired_at,uuid,token,invite_by_email,invite_user_id,plan_id,banned,remarks',
|
||||
'filter.*.key' => 'required|in:id,email,transfer_enable,d,expired_at,uuid,token,invite_by_email,invite_user_id,plan_id,banned,remarks,is_admin',
|
||||
'filter.*.condition' => 'required|in:>,<,=,>=,<=,模糊,!=',
|
||||
'filter.*.value' => 'required'
|
||||
];
|
||||
|
@ -29,7 +29,8 @@ class UserUpdate extends FormRequest
|
||||
'balance' => 'integer',
|
||||
'commission_type' => 'integer',
|
||||
'commission_balance' => 'integer',
|
||||
'remarks' => 'nullable'
|
||||
'remarks' => 'nullable',
|
||||
'speed_limit' => 'nullable|integer'
|
||||
];
|
||||
}
|
||||
|
||||
@ -59,7 +60,8 @@ class UserUpdate extends FormRequest
|
||||
'd.integer' => '下行流量格式不正确',
|
||||
'balance.integer' => '余额格式不正确',
|
||||
'commission_balance.integer' => '佣金格式不正确',
|
||||
'password.min' => '密码长度最小8位'
|
||||
'password.min' => '密码长度最小8位',
|
||||
'speed_limit.integer' => '限速格式不正确'
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ class AdminRoute
|
||||
public function map(Registrar $router)
|
||||
{
|
||||
$router->group([
|
||||
'prefix' => 'admin',
|
||||
'prefix' => config('v2board.secure_path', config('v2board.frontend_admin_path', 'admin')),
|
||||
'middleware' => 'admin'
|
||||
], function ($router) {
|
||||
// Config
|
||||
@ -28,6 +28,9 @@ class AdminRoute
|
||||
$router->get ('/server/group/fetch', 'Admin\\Server\\GroupController@fetch');
|
||||
$router->post('/server/group/save', 'Admin\\Server\\GroupController@save');
|
||||
$router->post('/server/group/drop', 'Admin\\Server\\GroupController@drop');
|
||||
$router->get ('/server/route/fetch', 'Admin\\Server\\RouteController@fetch');
|
||||
$router->post('/server/route/save', 'Admin\\Server\\RouteController@save');
|
||||
$router->post('/server/route/drop', 'Admin\\Server\\RouteController@drop');
|
||||
$router->get ('/server/manage/getNodes', 'Admin\\Server\\ManageController@getNodes');
|
||||
$router->post('/server/manage/sort', 'Admin\\Server\\ManageController@sort');
|
||||
$router->group([
|
||||
|
@ -14,7 +14,6 @@ class ClientRoute
|
||||
// Client
|
||||
$router->get('/subscribe', 'Client\\ClientController@subscribe');
|
||||
// App
|
||||
$router->get('/app/config', 'Client\\AppController@config');
|
||||
$router->get('/app/getConfig', 'Client\\AppController@getConfig');
|
||||
$router->get('/app/getVersion', 'Client\\AppController@getVersion');
|
||||
});
|
||||
|
@ -20,6 +20,7 @@ class PassportRoute
|
||||
// Comm
|
||||
$router->post('/comm/sendEmailVerify', 'Passport\\CommController@sendEmailVerify');
|
||||
$router->post('/comm/pv', 'Passport\\CommController@pv');
|
||||
$router->get ('/comm/config', 'Guest\\CommController@config'); // TODO:REMOVE:1.7.0
|
||||
});
|
||||
}
|
||||
}
|
||||
|
16
app/Models/ServerRoute.php
Executable file
16
app/Models/ServerRoute.php
Executable file
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class ServerRoute extends Model
|
||||
{
|
||||
protected $table = 'v2_server_route';
|
||||
protected $dateFormat = 'U';
|
||||
protected $guarded = ['id'];
|
||||
protected $casts = [
|
||||
'created_at' => 'timestamp',
|
||||
'updated_at' => 'timestamp',
|
||||
];
|
||||
}
|
@ -13,6 +13,7 @@ class ServerShadowsocks extends Model
|
||||
'created_at' => 'timestamp',
|
||||
'updated_at' => 'timestamp',
|
||||
'group_id' => 'array',
|
||||
'route_id' => 'array',
|
||||
'tags' => 'array',
|
||||
'obfs_settings' => 'array'
|
||||
];
|
||||
|
@ -13,6 +13,7 @@ class ServerTrojan extends Model
|
||||
'created_at' => 'timestamp',
|
||||
'updated_at' => 'timestamp',
|
||||
'group_id' => 'array',
|
||||
'route_id' => 'array',
|
||||
'tags' => 'array'
|
||||
];
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ class ServerV2ray extends Model
|
||||
'created_at' => 'timestamp',
|
||||
'updated_at' => 'timestamp',
|
||||
'group_id' => 'array',
|
||||
'route_id' => 'array',
|
||||
'tlsSettings' => 'array',
|
||||
'networkSettings' => 'array',
|
||||
'dnsSettings' => 'array',
|
||||
|
@ -32,6 +32,11 @@ class MGate {
|
||||
'label' => 'AppSecret',
|
||||
'description' => '',
|
||||
'type' => 'input',
|
||||
],
|
||||
'mgate_source_currency' => [
|
||||
'label' => '源货币',
|
||||
'description' => '默认CNY',
|
||||
'type' => 'input'
|
||||
]
|
||||
];
|
||||
}
|
||||
@ -44,6 +49,9 @@ class MGate {
|
||||
'notify_url' => $order['notify_url'],
|
||||
'return_url' => $order['return_url']
|
||||
];
|
||||
if (isset($this->config['mgate_source_currency'])) {
|
||||
$params['source_currency'] = $this->config['mgate_source_currency'];
|
||||
}
|
||||
$params['app_id'] = $this->config['mgate_app_id'];
|
||||
ksort($params);
|
||||
$str = http_build_query($params) . $this->config['mgate_app_secret'];
|
||||
|
54
app/Services/AuthService.php
Normal file
54
app/Services/AuthService.php
Normal file
@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
use App\Models\User;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
|
||||
class AuthService
|
||||
{
|
||||
private $user;
|
||||
|
||||
public function __construct($user)
|
||||
{
|
||||
$this->user = $user;
|
||||
}
|
||||
|
||||
public function generateAuthData($utm)
|
||||
{
|
||||
return [
|
||||
'token' => $this->user->token,
|
||||
'is_admin' => $this->user->is_admin,
|
||||
'auth_data' => JWT::encode([
|
||||
'expired_at' => time() + 3600,
|
||||
'id' => $this->user->id,
|
||||
'utm' => $utm,
|
||||
], config('app.key'), 'HS256')
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public static function decryptAuthData($jwt)
|
||||
{
|
||||
try {
|
||||
if (!Cache::has($jwt)) {
|
||||
$data = (array)JWT::decode($jwt, new Key(config('app.key'), 'HS256'));
|
||||
if ($data['expired_at'] < time()) return false;
|
||||
$user = User::select([
|
||||
'id',
|
||||
'email',
|
||||
'is_admin',
|
||||
'is_staff'
|
||||
])
|
||||
->find($data['id']);
|
||||
if (!$user) return false;
|
||||
Cache::put($jwt, $user->toArray(), 3600);
|
||||
}
|
||||
return Cache::get($jwt);
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
@ -71,6 +71,8 @@ class OrderService
|
||||
break;
|
||||
}
|
||||
|
||||
$this->setSpeedLimit($plan->speed_limit);
|
||||
|
||||
if (!$this->user->save()) {
|
||||
DB::rollBack();
|
||||
abort(500, '开通失败');
|
||||
@ -253,6 +255,11 @@ class OrderService
|
||||
return true;
|
||||
}
|
||||
|
||||
private function setSpeedLimit($speedLimit)
|
||||
{
|
||||
$this->user->speed_limit = $speedLimit;
|
||||
}
|
||||
|
||||
private function buyByResetTraffic()
|
||||
{
|
||||
$this->user->u = 0;
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace App\Services;
|
||||
|
||||
use App\Models\ServerLog;
|
||||
use App\Models\ServerRoute;
|
||||
use App\Models\ServerShadowsocks;
|
||||
use App\Models\User;
|
||||
use App\Models\ServerV2ray;
|
||||
@ -100,10 +101,13 @@ class ServerService
|
||||
);
|
||||
$tmp = array_column($servers, 'sort');
|
||||
array_multisort($tmp, SORT_ASC, $servers);
|
||||
$servers = array_map(function ($server) {
|
||||
$server['port'] = (int)$server['port'];
|
||||
return $server;
|
||||
}, $servers);
|
||||
return $servers;
|
||||
}
|
||||
|
||||
|
||||
public function getAvailableUsers($groupId)
|
||||
{
|
||||
return User::whereIn('group_id', $groupId)
|
||||
@ -179,7 +183,7 @@ class ServerService
|
||||
return $server->toArray();
|
||||
}
|
||||
|
||||
public function mergeData(&$servers)
|
||||
private function mergeData(&$servers)
|
||||
{
|
||||
foreach ($servers as $k => $v) {
|
||||
$serverType = strtoupper($servers[$k]['type']);
|
||||
@ -213,4 +217,23 @@ class ServerService
|
||||
array_multisort($tmp, SORT_ASC, $servers);
|
||||
return $servers;
|
||||
}
|
||||
|
||||
public function getRoutes(array $routeIds)
|
||||
{
|
||||
return ServerRoute::select(['id', 'match', 'action', 'action_value'])->whereIn('id', $routeIds)->get();
|
||||
}
|
||||
|
||||
public function getServer($serverId, $serverType)
|
||||
{
|
||||
switch ($serverType) {
|
||||
case 'v2ray':
|
||||
return ServerV2ray::find($serverId);
|
||||
case 'shadowsocks':
|
||||
return ServerShadowsocks::find($serverId);
|
||||
case 'trojan':
|
||||
return ServerTrojan::find($serverId);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,8 @@ class CacheKey
|
||||
'LAST_SEND_EMAIL_REMIND_TRAFFIC' => '最后发送流量邮件提醒',
|
||||
'SCHEDULE_LAST_CHECK_AT' => '计划任务最后检查时间',
|
||||
'REGISTER_IP_RATE_LIMIT' => '注册频率限制',
|
||||
'LAST_SEND_LOGIN_WITH_MAIL_LINK_TIMESTAMP' => '最后一次发送登入链接时间'
|
||||
'LAST_SEND_LOGIN_WITH_MAIL_LINK_TIMESTAMP' => '最后一次发送登入链接时间',
|
||||
'PASSWORD_ERROR_LIMIT' => '密码错误次数限制'
|
||||
];
|
||||
|
||||
public static function get(string $key, $uniqueValue)
|
||||
|
@ -4,6 +4,16 @@ namespace App\Utils;
|
||||
|
||||
class Helper
|
||||
{
|
||||
public static function uuidToBase64($uuid, $length)
|
||||
{
|
||||
return base64_encode(substr($uuid, 0, $length));
|
||||
}
|
||||
|
||||
public static function getShadowsocksServerKey($timestamp, $length)
|
||||
{
|
||||
return base64_encode(substr(md5($timestamp), 0, $length));
|
||||
}
|
||||
|
||||
public static function guid($format = false)
|
||||
{
|
||||
if (function_exists('com_create_guid') === true) {
|
||||
|
Reference in New Issue
Block a user