124 lines
3.2 KiB
PHP
124 lines
3.2 KiB
PHP
<?php
|
|
|
|
namespace Paymenter\Extensions\Others\ComplianceTools\Services;
|
|
|
|
use App\Helpers\ExtensionHelper;
|
|
use App\Models\User;
|
|
use Illuminate\Support\Facades\Hash;
|
|
use Paymenter\Extensions\Others\ComplianceTools\Models\SupportPin;
|
|
|
|
class SupportPinService
|
|
{
|
|
public function __construct(protected AuditLogService $auditLog)
|
|
{
|
|
}
|
|
|
|
public function generate(User $user): array
|
|
{
|
|
$extension = ExtensionHelper::getExtension('other', 'ComplianceTools');
|
|
$length = (int) ($extension?->config('pin_length') ?? 6);
|
|
$expiryMinutes = (int) ($extension?->config('pin_expiry_minutes') ?? 15);
|
|
|
|
$plainPin = $this->randomPin($length);
|
|
$lookup = hash('sha256', $plainPin);
|
|
|
|
SupportPin::query()
|
|
->where('user_id', $user->getKey())
|
|
->whereNull('revoked_at')
|
|
->update(['revoked_at' => now()]);
|
|
|
|
$pin = SupportPin::create([
|
|
'user_id' => $user->getKey(),
|
|
'pin_hash' => Hash::make($plainPin),
|
|
'pin_lookup' => $lookup,
|
|
'expires_at' => now()->addMinutes($expiryMinutes),
|
|
'created_ip' => request()->ip(),
|
|
'created_user_agent' => request()->header('User-Agent'),
|
|
]);
|
|
|
|
$this->auditLog->record(
|
|
category: 'support_pin',
|
|
event: 'generated',
|
|
context: [
|
|
'support_pin_id' => $pin->getKey(),
|
|
'expires_at' => $pin->expires_at?->toAtomString(),
|
|
],
|
|
subject: $user
|
|
);
|
|
|
|
return [$pin, $plainPin];
|
|
}
|
|
|
|
public function revoke(SupportPin $pin, ?User $actor = null): SupportPin
|
|
{
|
|
if ($pin->revoked_at) {
|
|
return $pin;
|
|
}
|
|
|
|
$pin->forceFill(['revoked_at' => now()])->save();
|
|
|
|
$this->auditLog->record(
|
|
category: 'support_pin',
|
|
event: 'revoked',
|
|
context: ['support_pin_id' => $pin->getKey()],
|
|
subject: $pin->user,
|
|
actor: $actor
|
|
);
|
|
|
|
return $pin;
|
|
}
|
|
|
|
public function validate(string $plainPin): ?SupportPin
|
|
{
|
|
$plainPin = strtoupper(trim($plainPin));
|
|
|
|
if ($plainPin === '') {
|
|
return null;
|
|
}
|
|
|
|
$lookup = hash('sha256', $plainPin);
|
|
|
|
$pin = SupportPin::query()
|
|
->where('pin_lookup', $lookup)
|
|
->first();
|
|
|
|
if (!$pin instanceof SupportPin) {
|
|
return null;
|
|
}
|
|
|
|
if (!Hash::check($plainPin, $pin->pin_hash)) {
|
|
return null;
|
|
}
|
|
|
|
if ($pin->revoked_at || $pin->expires_at->isPast()) {
|
|
return null;
|
|
}
|
|
|
|
$pin->forceFill(['last_validated_at' => now()])->save();
|
|
|
|
$this->auditLog->record(
|
|
category: 'support_pin',
|
|
event: 'validated',
|
|
context: [
|
|
'support_pin_id' => $pin->getKey(),
|
|
],
|
|
subject: $pin->user
|
|
);
|
|
|
|
return $pin;
|
|
}
|
|
|
|
protected function randomPin(int $length): string
|
|
{
|
|
$alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
|
$poolLength = strlen($alphabet) - 1;
|
|
|
|
$pin = '';
|
|
for ($i = 0; $i < $length; $i++) {
|
|
$pin .= $alphabet[random_int(0, $poolLength)];
|
|
}
|
|
|
|
return $pin;
|
|
}
|
|
}
|