mirror of
https://github.com/lkddi/Xboard.git
synced 2026-04-03 10:30:51 +08:00
Compare commits
8 Commits
a6c37bb112
...
76a800ddbb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76a800ddbb | ||
|
|
bbc96a18bc | ||
|
|
23294c1f93 | ||
|
|
130f7c82a8 | ||
|
|
0ab67c7a9b | ||
|
|
5512841ba2 | ||
|
|
7fbd1bb92d | ||
|
|
5dd4cd4bc9 |
@@ -43,7 +43,7 @@ class ResetPassword extends Command
|
||||
public function handle()
|
||||
{
|
||||
$password = $this->argument('password') ;
|
||||
$user = User::where('email', $this->argument('email'))->first();
|
||||
$user = User::byEmail($this->argument('email'))->first();
|
||||
if (!$user) abort(500, '邮箱不存在');
|
||||
$password = $password ?? Helper::guid(false);
|
||||
$user->password = password_hash($password, PASSWORD_DEFAULT);
|
||||
|
||||
@@ -29,7 +29,7 @@ class CommController extends Controller
|
||||
|
||||
// 检查白名单后缀限制
|
||||
if ((int) admin_setting('email_whitelist_enable', 0)) {
|
||||
$isRegisteredEmail = User::where('email', $email)->exists();
|
||||
$isRegisteredEmail = User::byEmail($email)->exists();
|
||||
if (!$isRegisteredEmail) {
|
||||
$allowedSuffixes = Helper::getEmailSuffix();
|
||||
$emailSuffix = substr(strrchr($email, '@'), 1);
|
||||
|
||||
@@ -74,6 +74,14 @@ class UserController extends Controller
|
||||
if (!$user->save()) {
|
||||
return $this->fail([400, __('Save failed')]);
|
||||
}
|
||||
|
||||
$currentToken = $user->currentAccessToken();
|
||||
if ($currentToken) {
|
||||
$user->tokens()->where('id', '!=', $currentToken->id)->delete();
|
||||
} else {
|
||||
$user->tokens()->delete();
|
||||
}
|
||||
|
||||
return $this->success(true);
|
||||
}
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ class OrderController extends Controller
|
||||
public function assign(OrderAssign $request)
|
||||
{
|
||||
$plan = Plan::find($request->input('plan_id'));
|
||||
$user = User::where('email', $request->input('email'))->first();
|
||||
$user = User::byEmail($request->input('email'))->first();
|
||||
|
||||
if (!$user) {
|
||||
return $this->fail([400202, '该用户不存在']);
|
||||
|
||||
@@ -220,7 +220,7 @@ class UserController extends Controller
|
||||
return $this->fail([400202, '用户不存在']);
|
||||
}
|
||||
if (isset($params['email'])) {
|
||||
if (User::where('email', $params['email'])->first() && $user->email !== $params['email']) {
|
||||
if (User::byEmail($params['email'])->first() && $user->email !== $params['email']) {
|
||||
return $this->fail([400201, '邮箱已被使用']);
|
||||
}
|
||||
}
|
||||
@@ -240,7 +240,7 @@ class UserController extends Controller
|
||||
$params['group_id'] = $plan->group_id;
|
||||
}
|
||||
// 处理邀请用户
|
||||
if ($request->input('invite_user_email') && $inviteUser = User::where('email', $request->input('invite_user_email'))->first()) {
|
||||
if ($request->input('invite_user_email') && $inviteUser = User::byEmail($request->input('invite_user_email'))->first()) {
|
||||
$params['invite_user_id'] = $inviteUser->id;
|
||||
} else {
|
||||
$params['invite_user_id'] = null;
|
||||
@@ -365,7 +365,7 @@ class UserController extends Controller
|
||||
if ($request->input('email_prefix')) {
|
||||
$email = $request->input('email_prefix') . '@' . $request->input('email_suffix');
|
||||
|
||||
if (User::where('email', $email)->exists()) {
|
||||
if (User::byEmail($email)->exists()) {
|
||||
return $this->fail([400201, '邮箱已存在于系统中']);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
namespace App\Models;
|
||||
|
||||
use App\Utils\Helper;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\Eloquent\Casts\Attribute;
|
||||
use Illuminate\Foundation\Auth\User as Authenticatable;
|
||||
use Laravel\Sanctum\HasApiTokens;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
@@ -81,6 +83,20 @@ class User extends Authenticatable
|
||||
public const COMMISSION_TYPE_SYSTEM = 0;
|
||||
public const COMMISSION_TYPE_PERIOD = 1;
|
||||
public const COMMISSION_TYPE_ONETIME = 2;
|
||||
protected function email(): Attribute
|
||||
{
|
||||
return Attribute::make(
|
||||
set: fn (string $value) => strtolower(trim($value)),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按邮箱查询(大小写不敏感,兼容所有数据库)
|
||||
*/
|
||||
public function scopeByEmail(Builder $query, string $email): Builder
|
||||
{
|
||||
return $query->where('email', strtolower(trim($email)));
|
||||
}
|
||||
|
||||
// 获取邀请人信息
|
||||
public function invite_user(): BelongsTo
|
||||
|
||||
@@ -61,7 +61,7 @@ class General extends AbstractProtocol
|
||||
$str = str_replace(
|
||||
['+', '/', '='],
|
||||
['-', '_', ''],
|
||||
base64_encode("{$protocol_settings['cipher']}:{$password}")
|
||||
base64_encode(data_get($protocol_settings, 'cipher') . ":{$password}")
|
||||
);
|
||||
$addr = Helper::wrapIPv6($server['host']);
|
||||
$plugin = data_get($protocol_settings, 'plugin');
|
||||
@@ -84,11 +84,11 @@ class General extends AbstractProtocol
|
||||
"port" => (string) $server['port'],
|
||||
"id" => $uuid,
|
||||
"aid" => '0',
|
||||
"net" => $server['protocol_settings']['network'],
|
||||
"net" => data_get($server, 'protocol_settings.network'),
|
||||
"type" => "none",
|
||||
"host" => "",
|
||||
"path" => "",
|
||||
"tls" => $protocol_settings['tls'] ? "tls" : "",
|
||||
"tls" => data_get($protocol_settings, 'tls') ? "tls" : "",
|
||||
];
|
||||
if ($serverName = data_get($protocol_settings, 'tls_settings.server_name')) {
|
||||
$config['sni'] = $serverName;
|
||||
@@ -97,7 +97,7 @@ class General extends AbstractProtocol
|
||||
$config['fp'] = $fp;
|
||||
}
|
||||
|
||||
switch ($protocol_settings['network']) {
|
||||
switch (data_get($protocol_settings, 'network')) {
|
||||
case 'tcp':
|
||||
if (data_get($protocol_settings, 'network_settings.header.type', 'none') !== 'none') {
|
||||
$config['type'] = data_get($protocol_settings, 'network_settings.header.type', 'http');
|
||||
@@ -152,11 +152,11 @@ class General extends AbstractProtocol
|
||||
'mode' => 'multi', //grpc传输模式
|
||||
'security' => '', //传输层安全 tls/reality
|
||||
'encryption' => 'none', //加密方式
|
||||
'type' => $server['protocol_settings']['network'], //传输协议
|
||||
'type' => data_get($server, 'protocol_settings.network'), //传输协议
|
||||
'flow' => data_get($protocol_settings, 'flow'),
|
||||
];
|
||||
// 处理TLS
|
||||
switch ($server['protocol_settings']['tls']) {
|
||||
switch (data_get($server, 'protocol_settings.tls')) {
|
||||
case 1:
|
||||
$config['security'] = "tls";
|
||||
if ($fp = Helper::getTlsFingerprint(data_get($protocol_settings, 'utls'))) {
|
||||
@@ -184,7 +184,7 @@ class General extends AbstractProtocol
|
||||
break;
|
||||
}
|
||||
// 处理传输协议
|
||||
switch ($server['protocol_settings']['network']) {
|
||||
switch (data_get($server, 'protocol_settings.network')) {
|
||||
case 'ws':
|
||||
if ($path = data_get($protocol_settings, 'network_settings.path'))
|
||||
$config['path'] = $path;
|
||||
@@ -256,7 +256,7 @@ class General extends AbstractProtocol
|
||||
break;
|
||||
}
|
||||
|
||||
switch ($server['protocol_settings']['network']) {
|
||||
switch (data_get($server, 'protocol_settings.network')) {
|
||||
case 'ws':
|
||||
$array['type'] = 'ws';
|
||||
if ($path = data_get($protocol_settings, 'network_settings.path'))
|
||||
|
||||
@@ -46,7 +46,7 @@ class QuantumultX extends AbstractProtocol
|
||||
$addr = Helper::wrapIPv6($server['host']);
|
||||
$config = [
|
||||
"shadowsocks={$addr}:{$server['port']}",
|
||||
"method={$protocol_settings['cipher']}",
|
||||
"method=" . data_get($protocol_settings, 'cipher'),
|
||||
"password={$password}",
|
||||
];
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ class Shadowrocket extends AbstractProtocol
|
||||
$str = str_replace(
|
||||
['+', '/', '='],
|
||||
['-', '_', ''],
|
||||
base64_encode("{$protocol_settings['cipher']}:{$password}")
|
||||
base64_encode(data_get($protocol_settings, 'cipher') . ":{$password}")
|
||||
);
|
||||
$addr = Helper::wrapIPv6($server['host']);
|
||||
|
||||
@@ -98,7 +98,7 @@ class Shadowrocket extends AbstractProtocol
|
||||
'remark' => $server['name'],
|
||||
'alterId' => 0
|
||||
];
|
||||
if ($protocol_settings['tls']) {
|
||||
if (data_get($protocol_settings, 'tls')) {
|
||||
$config['tls'] = 1;
|
||||
if (data_get($protocol_settings, 'tls_settings')) {
|
||||
if (!!data_get($protocol_settings, 'tls_settings.allow_insecure'))
|
||||
@@ -352,7 +352,7 @@ class Shadowrocket extends AbstractProtocol
|
||||
}
|
||||
$params['insecure'] = data_get($protocol_settings, 'tls.allow_insecure');
|
||||
if (isset($protocol_settings['hop_interval'])) {
|
||||
$params['keepalive'] = $protocol_settings['hop_interval'];
|
||||
$params['keepalive'] = data_get($protocol_settings, 'hop_interval');
|
||||
}
|
||||
if (isset($server['ports'])) {
|
||||
$params['mport'] = $server['ports'];
|
||||
|
||||
@@ -434,8 +434,8 @@ class SingBox extends AbstractProtocol
|
||||
$array['flow'] = $flow;
|
||||
}
|
||||
|
||||
if ($protocol_settings['tls']) {
|
||||
$tlsMode = (int) $protocol_settings['tls'];
|
||||
if (data_get($protocol_settings, 'tls')) {
|
||||
$tlsMode = (int) data_get($protocol_settings, 'tls', 0);
|
||||
$tlsConfig = [
|
||||
'enabled' => true,
|
||||
'insecure' => $tlsMode === 2
|
||||
|
||||
@@ -89,7 +89,7 @@ class Surfboard extends AbstractProtocol
|
||||
"{$server['name']}=ss",
|
||||
"{$server['host']}",
|
||||
"{$server['port']}",
|
||||
"encrypt-method={$protocol_settings['cipher']}",
|
||||
"encrypt-method=" . data_get($protocol_settings, 'cipher'),
|
||||
"password={$password}",
|
||||
'tfo=true',
|
||||
'udp-relay=true'
|
||||
|
||||
@@ -36,7 +36,7 @@ class LoginService
|
||||
}
|
||||
|
||||
// 查找用户
|
||||
$user = User::where('email', $email)->first();
|
||||
$user = User::byEmail($email)->first();
|
||||
if (!$user) {
|
||||
return [false, [400, __('Incorrect email or password')]];
|
||||
}
|
||||
@@ -99,7 +99,7 @@ class LoginService
|
||||
}
|
||||
|
||||
// 查找用户
|
||||
$user = User::where('email', $email)->first();
|
||||
$user = User::byEmail($email)->first();
|
||||
if (!$user) {
|
||||
return [false, [400, __('This email is not registered in the system')]];
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class MailLinkService
|
||||
return [false, [429, __('Sending frequently, please try again later')]];
|
||||
}
|
||||
|
||||
$user = User::where('email', $email)->first();
|
||||
$user = User::byEmail($email)->first();
|
||||
if (!$user) {
|
||||
return [true, true]; // 成功但用户不存在,保护用户隐私
|
||||
}
|
||||
|
||||
@@ -91,8 +91,7 @@ class RegisterService
|
||||
}
|
||||
|
||||
// 检查邮箱是否存在
|
||||
$email = $request->input('email');
|
||||
$exist = User::where('email', $email)->first();
|
||||
$exist = User::byEmail($request->input('email'))->first();
|
||||
if ($exist) {
|
||||
return [false, [400201, __('Email already exists')]];
|
||||
}
|
||||
|
||||
@@ -29,7 +29,9 @@ class TelegramService
|
||||
|
||||
public function sendMessage(int $chatId, string $text, string $parseMode = ''): void
|
||||
{
|
||||
$text = $parseMode === 'markdown' ? str_replace('_', '\_', $text) : $text;
|
||||
if ($parseMode === 'markdown') {
|
||||
$text = $this->escapeMarkdown($text);
|
||||
}
|
||||
|
||||
$this->request('sendMessage', [
|
||||
'chat_id' => $chatId,
|
||||
@@ -38,6 +40,26 @@ class TelegramService
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 转义 Telegram Markdown 特殊字符
|
||||
*/
|
||||
protected function escapeMarkdown(string $text): string
|
||||
{
|
||||
$escapeChars = ['_', '*', '`', '['];
|
||||
$escapedText = '';
|
||||
|
||||
for ($i = 0; $i < strlen($text); $i++) {
|
||||
$char = $text[$i];
|
||||
if (in_array($char, $escapeChars, true)) {
|
||||
$escapedText .= '\\' . $char;
|
||||
} else {
|
||||
$escapedText .= $char;
|
||||
}
|
||||
}
|
||||
|
||||
return $escapedText;
|
||||
}
|
||||
|
||||
public function approveChatJoinRequest(int $chatId, int $userId): void
|
||||
{
|
||||
$this->request('approveChatJoinRequest', [
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
// 统计需要转换的记录数
|
||||
$count = DB::table('v2_user')
|
||||
->whereNotNull('email')
|
||||
->whereRaw('email != LOWER(email)')
|
||||
->count();
|
||||
|
||||
if ($count > 0) {
|
||||
Log::info("Converting {$count} email(s) to lowercase");
|
||||
DB::table('v2_user')
|
||||
->whereNotNull('email')
|
||||
->whereRaw('email != LOWER(email)')
|
||||
->update(['email' => DB::raw('LOWER(email)')]);
|
||||
|
||||
Log::info("Email lowercase conversion completed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
// 无法恢复原始大小写
|
||||
}
|
||||
};
|
||||
148
resources/lang/ru-RU.json
Normal file
148
resources/lang/ru-RU.json
Normal file
@@ -0,0 +1,148 @@
|
||||
{
|
||||
"Article does not exist": "Статья не существует",
|
||||
"Cancel failed": "Ошибка отмены",
|
||||
"Close failed": "Ошибка закрытия",
|
||||
"Coupon cannot be empty": "Купон не может быть пустым",
|
||||
"Coupon failed": "Ошибка купона",
|
||||
"Currency conversion has timed out, please try again later": "Время конвертации валюты истекло, попробуйте позже",
|
||||
"Email already exists": "Эл. почта уже существует",
|
||||
"Email suffix is not in the Whitelist": "Суффикс эл. почты не в белом списке",
|
||||
"Email suffix is not in whitelist": "Суффикс эл. почты не в белом списке",
|
||||
"Email verification code": "Код подтверждения эл. почты",
|
||||
"Email verification code cannot be empty": "Код подтверждения эл. почты не может быть пустым",
|
||||
"Email verification code has been sent, please request again later": "Код подтверждения отправлен, запросите повторно позже",
|
||||
"Failed to create order": "Не удалось создать заказ",
|
||||
"Failed to open ticket": "Не удалось открыть тикет",
|
||||
"Gmail alias is not supported": "Псевдоним Gmail не поддерживается",
|
||||
"Incorrect email or password": "Неверная эл. почта или пароль",
|
||||
"Incorrect email verification code": "Неверный код подтверждения эл. почты",
|
||||
"Insufficient balance": "Недостаточно средств",
|
||||
"Insufficient commission balance": "Недостаточно комиссии",
|
||||
"Invalid code is incorrect": "Неверный код",
|
||||
"Invalid coupon": "Недействительный купон",
|
||||
"Invalid invitation code": "Недействительный код приглашения",
|
||||
"Invalid parameter": "Недопустимый параметр",
|
||||
"Message cannot be empty": "Сообщение не может быть пустым",
|
||||
"No active subscription. Unable to use our provided Apple ID": "Нет активной подписки. Невозможно использовать предоставленный Apple ID",
|
||||
"Oops, there's a problem... Please refresh the page and try again later": "Ой, возникла проблема... Обновите страницу и попробуйте позже",
|
||||
"Order does not exist": "Заказ не существует",
|
||||
"Order does not exist or has been paid": "Заказ не существует или уже оплачен",
|
||||
"Payment failed. Please check your credit card information": "Ошибка оплаты. Проверьте данные карты",
|
||||
"Payment gateway request failed": "Ошибка запроса к платёжному шлюзу",
|
||||
"Payment method is not available": "Способ оплаты недоступен",
|
||||
"Please wait for the technical enginneer to reply": "Ожидайте ответа технического специалиста",
|
||||
"Register failed": "Ошибка регистрации",
|
||||
"Registration has closed": "Регистрация закрыта",
|
||||
"Reset failed": "Ошибка сброса",
|
||||
"Save failed": "Ошибка сохранения",
|
||||
"Subscription has expired or no active subscription, unable to purchase Data Reset Package": "Подписка истекла или нет активной подписки, невозможно приобрести пакет сброса данных",
|
||||
"Subscription plan does not exist": "Тарифный план не существует",
|
||||
"The coupon code cannot be used for this subscription": "Код купона не может быть использован для этой подписки",
|
||||
"The current required minimum withdrawal commission is :limit": "Текущая минимальная комиссия для вывода: :limit",
|
||||
"The maximum number of creations has been reached": "Достигнуто максимальное количество созданий",
|
||||
"The old password is wrong": "Неверный старый пароль",
|
||||
"The ticket is closed and cannot be replied": "Тикет закрыт, ответ невозможен",
|
||||
"The user does not exist": "Пользователь не существует",
|
||||
"There are other unresolved tickets": "Есть другие нерешённые тикеты",
|
||||
"This coupon has expired": "Этот купон истёк",
|
||||
"This coupon has not yet started": "Этот купон ещё не начался",
|
||||
"This coupon is no longer available": "Этот купон больше недоступен",
|
||||
"This email is not registered in the system": "Эта эл. почта не зарегистрирована в системе",
|
||||
"This payment cycle cannot be purchased, please choose another cycle": "Этот платёжный цикл нельзя приобрести, выберите другой",
|
||||
"This subscription cannot be renewed, please change to another subscription": "Эту подписку нельзя продлить, выберите другую",
|
||||
"This subscription has been sold out, please choose another subscription": "Эта подписка распродана, выберите другую",
|
||||
"This subscription has expired, please change to another subscription": "Эта подписка истекла, выберите другую",
|
||||
"Ticket does not exist": "Тикет не существует",
|
||||
"Ticket reply failed": "Ошибка ответа на тикет",
|
||||
"Token error": "Ошибка токена",
|
||||
"Transfer failed": "Ошибка перевода",
|
||||
"Unsupported withdrawal": "Вывод не поддерживается",
|
||||
"Unsupported withdrawal method": "Способ вывода не поддерживается",
|
||||
"Withdrawal account": "Счёт для вывода",
|
||||
"Withdrawal method": "Способ вывода",
|
||||
"You can only cancel pending orders": "Можно отменить только ожидающие заказы",
|
||||
"You have an unpaid or pending order, please try again later or cancel it": "У вас есть неоплаченный или ожидающий заказ, попробуйте позже или отмените его",
|
||||
"You must have a valid subscription to view content in this area": "Необходима действующая подписка для просмотра контента",
|
||||
"You must use the invitation code to register": "Для регистрации необходимо использовать код приглашения",
|
||||
"Your account has been suspended": "Ваш аккаунт приостановлен",
|
||||
"[Commission Withdrawal Request] This ticket is opened by the system": "[Запрос на вывод комиссии] Тикет создан системой",
|
||||
"Plan ID cannot be empty": "ID тарифа не может быть пустым",
|
||||
"Plan cycle cannot be empty": "Цикл тарифа не может быть пустым",
|
||||
"Wrong plan cycle": "Неверный цикл тарифа",
|
||||
"Ticket subject cannot be empty": "Тема тикета не может быть пустой",
|
||||
"Ticket level cannot be empty": "Уровень тикета не может быть пустым",
|
||||
"Incorrect ticket level format": "Неверный формат уровня тикета",
|
||||
"The withdrawal method cannot be empty": "Способ вывода не может быть пустым",
|
||||
"The withdrawal account cannot be empty": "Счёт для вывода не может быть пустым",
|
||||
"Old password cannot be empty": "Старый пароль не может быть пустым",
|
||||
"New password cannot be empty": "Новый пароль не может быть пустым",
|
||||
"Password must be greater than 8 digits": "Пароль должен быть длиннее 8 символов",
|
||||
"The transfer amount cannot be empty": "Сумма перевода не может быть пустой",
|
||||
"The transfer amount parameter is wrong": "Неверный параметр суммы перевода",
|
||||
"Incorrect format of expiration reminder": "Неверный формат напоминания об истечении",
|
||||
"Incorrect traffic alert format": "Неверный формат оповещения о трафике",
|
||||
"Email can not be empty": "Эл. почта не может быть пустой",
|
||||
"Email format is incorrect": "Неверный формат эл. почты",
|
||||
"Password can not be empty": "Пароль не может быть пустым",
|
||||
"The traffic usage in :app_name has reached 80%": "Использование трафика в :app_name достигло 80%",
|
||||
"The service in :app_name is about to expire": "Сервис в :app_name скоро истекает",
|
||||
"The coupon can only be used :limit_use_with_user per person": "Купон можно использовать только :limit_use_with_user раз на человека",
|
||||
"The coupon code cannot be used for this period": "Код купона не может быть использован для этого периода",
|
||||
"Request failed, please try again later": "Ошибка запроса, попробуйте позже",
|
||||
"Register frequently, please try again after :minute minute": "Регистрация слишком частая, попробуйте через :minute минуту",
|
||||
"Uh-oh, we've had some problems, we're working on it.": "Ой, у нас возникли проблемы, мы работаем над этим",
|
||||
"This subscription reset package does not apply to your subscription": "Этот пакет сброса не适用于 вашей подписки",
|
||||
"Login to :name": "Вход в :name",
|
||||
"Sending frequently, please try again later": "Отправка слишком частая, попробуйте позже",
|
||||
"Current product is sold out": "Товар распродан",
|
||||
"There are too many password errors, please try again after :minute minutes.": "Слишком много ошибок пароля, попробуйте через :minute минут",
|
||||
"Reset failed, Please try again later": "Ошибка сброса, попробуйте позже",
|
||||
"Subscribe": "Подписаться",
|
||||
"User Information": "Информация о пользователе",
|
||||
"Username": "Имя пользователя",
|
||||
"Status": "Статус",
|
||||
"Active": "Активен",
|
||||
"Inactive": "Неактивен",
|
||||
"Data Used": "Использовано данных",
|
||||
"Data Limit": "Лимит данных",
|
||||
"Expiration Date": "Дата истечения",
|
||||
"Reset In": "Сброс через",
|
||||
"Days": "Дней",
|
||||
"Subscription Link": "Ссылка подписки",
|
||||
"Copy": "Копировать",
|
||||
"Copied": "Скопировано",
|
||||
"QR Code": "QR-код",
|
||||
"Unlimited": "Без ограничений",
|
||||
"Device Limit": "Лимит устройств",
|
||||
"Devices": "Устройства",
|
||||
"No Limit": "Без лимита",
|
||||
"First Day of Month": "Первый день месяца",
|
||||
"Monthly": "Ежемесячно",
|
||||
"Never": "Никогда",
|
||||
"First Day of Year": "Первый день года",
|
||||
"Yearly": "Ежегодно",
|
||||
"update.local_newer": "Текущая версия новее удалённой, сначала закоммитьте изменения",
|
||||
"update.already_latest": "Уже установлена последняя версия",
|
||||
"update.process_running": "Процесс обновления уже запущен",
|
||||
"update.success": "Обновление успешно, с :from до :to, система перезагрузится автоматически",
|
||||
"update.failed": "Ошибка обновления: :error",
|
||||
"update.backup_failed": "Ошибка резервного копирования БД: :error",
|
||||
"update.code_update_failed": "Ошибка обновления кода: :error",
|
||||
"update.migration_failed": "Ошибка миграции БД: :error",
|
||||
"update.cache_clear_failed": "Ошибка очистки кэша: :error",
|
||||
"update.flag_create_failed": "Не удалось создать флаг обновления: :error",
|
||||
"traffic_reset.reset_type.monthly": "Ежемесячный сброс",
|
||||
"traffic_reset.reset_type.first_day_month": "Сброс в первый день месяца",
|
||||
"traffic_reset.reset_type.yearly": "Ежегодный сброс",
|
||||
"traffic_reset.reset_type.first_day_year": "Сброс в первый день года",
|
||||
"traffic_reset.reset_type.manual": "Ручной сброс",
|
||||
"traffic_reset.reset_type.purchase": "Приобретение пакета сброса",
|
||||
"traffic_reset.source.auto": "Автоматический запуск",
|
||||
"traffic_reset.source.manual": "Ручной запуск",
|
||||
"traffic_reset.source.api": "Вызов API",
|
||||
"traffic_reset.source.cron": "Cron-задача",
|
||||
"traffic_reset.source.user_access": "Доступ пользователя",
|
||||
"traffic_reset.reset_success": "Трафик успешно сброшен",
|
||||
"traffic_reset.reset_failed": "Ошибка сброса трафика, подробности в логах",
|
||||
"traffic_reset.user_cannot_reset": "Пользователь не может сбросить трафик (аккаунт не активен или нет действующего тарифа)"
|
||||
}
|
||||
@@ -21,7 +21,10 @@ use Illuminate\Support\Facades\File;
|
||||
|
||||
Route::get('/', function (Request $request) {
|
||||
if (admin_setting('app_url') && admin_setting('safe_mode_enable', 0)) {
|
||||
if ($request->server('HTTP_HOST') !== parse_url(admin_setting('app_url'))['host']) {
|
||||
$requestHost = $request->getHost();
|
||||
$configHost = parse_url(admin_setting('app_url'), PHP_URL_HOST);
|
||||
|
||||
if ($requestHost !== $configHost) {
|
||||
abort(403);
|
||||
}
|
||||
}
|
||||
|
||||
2
theme/Xboard/assets/umi.js
vendored
2
theme/Xboard/assets/umi.js
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user