php-commerce/Data/FraudAssessment.php
Snider 2e5cd499b9 security: complete rate limiting and fraud service implementation (P1-040)
Add missing files from P1-040/P1-041 implementation:
- CheckoutRateLimitException for 429 responses when rate limit exceeded
- FraudAssessment data object for fraud scoring results
- FraudService for velocity checks and Stripe Radar integration
- Register services in Boot.php
- Add fraud detection configuration in config.php
- Add CouponServiceTest for input sanitisation

The CheckoutRateLimiter (already tracked) is now properly integrated with
the exception handling, and the FraudService provides defence-in-depth
with velocity-based and geo-anomaly detection.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 16:09:29 +00:00

82 lines
2.2 KiB
PHP

<?php
declare(strict_types=1);
namespace Core\Mod\Commerce\Data;
/**
* Fraud assessment result.
*
* Contains risk level, signals, and recommended actions based on
* fraud detection analysis from Stripe Radar and internal checks.
*/
class FraudAssessment
{
public function __construct(
public readonly string $riskLevel,
public readonly array $signals,
public readonly string $source,
public readonly ?int $stripeRiskScore = null,
public readonly bool $shouldBlock = false,
public readonly bool $shouldReview = false,
) {}
/**
* Create a not-assessed result (fraud detection disabled).
*/
public static function notAssessed(): self
{
return new self(
riskLevel: 'not_assessed',
signals: [],
source: 'none',
shouldBlock: false,
shouldReview: false
);
}
/**
* Check if this is a high-risk assessment.
*/
public function isHighRisk(): bool
{
return $this->riskLevel === 'highest' || $this->riskLevel === 'elevated';
}
/**
* Check if fraud detection was performed.
*/
public function wasAssessed(): bool
{
return $this->riskLevel !== 'not_assessed';
}
/**
* Get a human-readable risk description.
*/
public function getRiskDescription(): string
{
return match ($this->riskLevel) {
'highest' => 'Very High Risk - Payment appears fraudulent',
'elevated' => 'Elevated Risk - Payment requires review',
'normal' => 'Normal Risk - Payment appears legitimate',
'not_assessed' => 'Not Assessed - Fraud detection disabled',
default => 'Unknown Risk Level',
};
}
/**
* Convert to array for storage/logging.
*/
public function toArray(): array
{
return [
'risk_level' => $this->riskLevel,
'signals' => $this->signals,
'source' => $this->source,
'stripe_risk_score' => $this->stripeRiskScore,
'should_block' => $this->shouldBlock,
'should_review' => $this->shouldReview,
];
}
}