85 lines
3.9 KiB
PHP
85 lines
3.9 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Business;
|
|
|
|
use App\Services\StoreAccountPasswordClient;
|
|
use App\Utilities\SidebarPermissions;
|
|
use App\Utilities\SystemAccess;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Routing\Controller;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Facades\RateLimiter;
|
|
use Illuminate\Support\Str;
|
|
use Modules\EcommerceFinance\Repositories\StoreAccountMirrorRepository;
|
|
use Throwable;
|
|
|
|
class StoreAccountPasswords extends Controller
|
|
{
|
|
public function reveal(string $account, Request $request, StoreAccountMirrorRepository $accounts, StoreAccountPasswordClient $client)
|
|
{
|
|
if (app()->bound('debugbar')) {
|
|
app('debugbar')->disable();
|
|
}
|
|
$requestId = (string) Str::uuid();
|
|
$purpose = $request->input('purpose');
|
|
if (! preg_match('/^[A-Za-z0-9_-]{1,128}$/D', $account)
|
|
|| ! in_array($purpose, ['view', 'copy'], true)
|
|
|| array_diff(array_keys($request->all()), ['purpose', '_token']) !== [] || $request->query() !== []) {
|
|
return $this->respond(422, $requestId);
|
|
}
|
|
try {
|
|
DB::table('store_account_password_audits')->insert([
|
|
'request_id' => $requestId, 'actor_user_id' => $request->user()->id,
|
|
'company_id' => company_id(), 'store_account_id' => $account,
|
|
'purpose' => $purpose, 'created_at' => now(),
|
|
]);
|
|
} catch (Throwable) {
|
|
return $this->respond(503, $requestId);
|
|
}
|
|
|
|
$result = ['status' => 503];
|
|
try {
|
|
$pages = collect(SidebarPermissions::navigationFor($request->user()))->firstWhere('slug', 'store-management');
|
|
// Re-read role membership for every secret request; a cached admin
|
|
// role must not survive a permission revocation.
|
|
if (! $request->user()->roles()->whereIn('roles.name', [SystemAccess::SUPER_ADMIN, SystemAccess::ADMIN])->exists()
|
|
|| ! collect($pages['pages'] ?? [])->contains('slug', 'store-accounts')) {
|
|
$result = ['status' => 403];
|
|
} elseif (RateLimiter::tooManyAttempts('store-password:'.$request->user()->id, 10)) {
|
|
$result = ['status' => 429];
|
|
} else {
|
|
RateLimiter::hit('store-password:'.$request->user()->id, 60);
|
|
$result = $accounts->containsAccount($account)
|
|
? $client->reveal($account, $request->user()->id, $purpose)
|
|
: ['status' => 404];
|
|
}
|
|
} catch (Throwable) {
|
|
$result = ['status' => 503];
|
|
}
|
|
try {
|
|
$saved = DB::table('store_account_password_audits')->where('request_id', $requestId)->update([
|
|
'status' => $result['status'], 'upstream_request_id' => $result['upstream_request_id'] ?? null,
|
|
'completed_at' => now(),
|
|
]);
|
|
if ($saved !== 1) {
|
|
return $this->respond(503, $requestId);
|
|
}
|
|
} catch (Throwable) {
|
|
return $this->respond(503, $requestId);
|
|
}
|
|
return $this->respond($result['status'], $requestId, $result['password'] ?? null);
|
|
}
|
|
|
|
private function respond(int $status, string $requestId, ?string $password = null)
|
|
{
|
|
$messages = [403 => '当前账号没有查看店铺密码的权限。', 404 => '该账号暂无可读取的密码。',
|
|
422 => '请求无效,请刷新页面后重试。', 429 => '操作过于频繁,请稍后再试。',
|
|
503 => '密码服务暂不可用,请稍后再试或联系管理员。'];
|
|
return response()->json($status === 200
|
|
? ['password' => $password, 'requestId' => $requestId]
|
|
: ['message' => $messages[$status] ?? $messages[503], 'requestId' => $requestId], $status)
|
|
->withHeaders(['Cache-Control' => 'no-store, private', 'Pragma' => 'no-cache',
|
|
'X-Content-Type-Options' => 'nosniff', 'Referrer-Policy' => 'no-referrer']);
|
|
}
|
|
}
|