69 lines
2.7 KiB
PHP
69 lines
2.7 KiB
PHP
<?php
|
|
|
|
namespace Modules\Core\Auth\Privacy;
|
|
|
|
use Modules\Core\Auth\Models\UserSession;
|
|
use Modules\Core\Privacy\Contracts\PersonalDataProvider;
|
|
use Modules\Core\Privacy\DTOs\CustomerSubject;
|
|
use Modules\Core\Privacy\Enums\ErasureOutcome;
|
|
use Modules\Core\Privacy\DTOs\ProviderErasureResult;
|
|
use Modules\Core\Privacy\DTOs\ProviderExportResult;
|
|
use Modules\Core\Privacy\DTOs\UserSubject;
|
|
|
|
/**
|
|
* Login-session device/location metadata (user_sessions) — ip_address and
|
|
* user_agent are device/location fingerprinting data tied 1:1 to a User via
|
|
* user_id, never to a Customer (business account), so this is User-scope
|
|
* only. No legal retention requirement applies to session metadata the way
|
|
* it does to Order (there's no tax/accounting reason to keep old login IPs
|
|
* around), so rows are deleted outright rather than pseudonymized.
|
|
*
|
|
* A hard delete here is safe regardless of whether the User row itself has
|
|
* already been erased — CustomerDataProvider::eraseForUser() nulls the
|
|
* User's own name/email but never touches user_sessions, and the table's
|
|
* own user_id FK is cascadeOnDelete() only if the User row itself were
|
|
* hard-deleted, which it never is (erasure here means "identity nulled,"
|
|
* not "row removed" — see docs/modules.md "Customer/User Pairing").
|
|
*/
|
|
class UserSessionDataProvider implements PersonalDataProvider
|
|
{
|
|
public function name(): string
|
|
{
|
|
return 'sessions';
|
|
}
|
|
|
|
public function exportForCustomer(CustomerSubject $subject): ProviderExportResult
|
|
{
|
|
return new ProviderExportResult('sessions', []);
|
|
}
|
|
|
|
public function exportForUser(UserSubject $subject): ProviderExportResult
|
|
{
|
|
$sessions = UserSession::where('user_id', $subject->userId)->get();
|
|
|
|
return new ProviderExportResult('sessions', $sessions->map(fn (UserSession $session) => [
|
|
'id' => $session->id,
|
|
'ip_address' => $session->ip_address,
|
|
'user_agent' => $session->user_agent,
|
|
'last_used_at' => $session->last_used_at?->toIso8601String(),
|
|
'revoked_at' => $session->revoked_at?->toIso8601String(),
|
|
])->all());
|
|
}
|
|
|
|
public function eraseForCustomer(CustomerSubject $subject): ProviderErasureResult
|
|
{
|
|
return new ProviderErasureResult('sessions', ErasureOutcome::Skipped, 'Login sessions belong to individual Users, not Customer accounts.');
|
|
}
|
|
|
|
public function eraseForUser(UserSubject $subject): ProviderErasureResult
|
|
{
|
|
$deleted = UserSession::where('user_id', $subject->userId)->delete();
|
|
|
|
if ($deleted === 0) {
|
|
return new ProviderErasureResult('sessions', ErasureOutcome::Skipped, 'No login sessions for this user.');
|
|
}
|
|
|
|
return new ProviderErasureResult('sessions', ErasureOutcome::Erased);
|
|
}
|
|
}
|