CaiWuXiTong/app/Services/StoreAccountPasswordClient.php

65 lines
2.8 KiB
PHP

<?php
namespace App\Services;
use GuzzleHttp\Client;
use GuzzleHttp\ClientInterface;
use Throwable;
class StoreAccountPasswordClient
{
private ClientInterface $http;
public function __construct(?ClientInterface $http = null)
{
// Dedicated transport: do not dispatch Laravel HTTP logging events or
// attach the application's general request/response collectors.
$this->http = $http ?? new Client();
}
public function reveal(string $accountId, int $actorId, string $purpose): array
{
$template = (string) config('store_account_password.url');
$token = (string) config('store_account_password.token');
if (substr_count($template, '{id}') !== 1 || parse_url($template, PHP_URL_SCHEME) !== 'https'
|| ! preg_match('/^[A-Za-z0-9_-]{43,128}$/D', $token)) {
return ['status' => 503];
}
try {
$response = $this->http->request('POST', str_replace('{id}', rawurlencode($accountId), $template), [
'headers' => ['Authorization' => 'Bearer '.$token, 'Accept' => 'application/json'],
'json' => ['requesterId' => 'finance-user-'.$actorId, 'purpose' => $purpose],
'verify' => true, 'allow_redirects' => false, 'http_errors' => false,
'connect_timeout' => 3, 'timeout' => 10,
'sink' => fopen('php://memory', 'w+'),
]);
$status = $response->getStatusCode();
if ($response->getBody()->isSeekable()) {
$response->getBody()->rewind();
}
$body = $response->getBody()->read(65537);
$response->getBody()->close();
if (strlen($body) > 65536) {
return ['status' => 503];
}
$data = json_decode($body, true);
unset($body);
$requestId = $data['requestId'] ?? null;
if (! is_string($requestId) || ! preg_match('/^[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}$/iD', $requestId)) {
$requestId = null;
}
if ($status !== 200) {
return ['status' => in_array($status, [404, 429], true) ? $status : 503, 'upstream_request_id' => $requestId];
}
if (! $requestId || ! preg_match('/(?:^|,)\s*no-store\s*(?:,|$)/i', $response->getHeaderLine('Cache-Control'))
|| ! is_string($data['password'] ?? null) || $data['password'] === '') {
return ['status' => 503, 'upstream_request_id' => $requestId];
}
return ['status' => 200, 'password' => $data['password'], 'upstream_request_id' => $requestId];
} catch (Throwable) {
// Never log exception objects: transport errors may contain response bodies.
return ['status' => 503];
}
}
}