You've already forked wc-licensed-product-client
Fix security vulnerabilities identified in audit
- Add JSON encoding error handling in ResponseSignature to prevent silent failures - Sanitize exception messages to prevent information disclosure - Fix header normalization to treat empty values as null - Add SSRF protection with URL validation and private IP blocking - Replace custom key derivation with RFC 5869 compliant hash_hkdf() - Add input validation in DTO fromArray() methods - Add DateTime exception handling in DTOs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,13 @@ final readonly class ActivationResult
|
||||
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
if (!isset($data['success']) || !is_bool($data['success'])) {
|
||||
throw new \InvalidArgumentException('Invalid response: missing or invalid success field');
|
||||
}
|
||||
if (!isset($data['message']) || !is_string($data['message'])) {
|
||||
throw new \InvalidArgumentException('Invalid response: missing or invalid message field');
|
||||
}
|
||||
|
||||
return new self(
|
||||
success: $data['success'],
|
||||
message: $data['message'],
|
||||
|
||||
@@ -15,9 +15,21 @@ final readonly class LicenseInfo
|
||||
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
if (!isset($data['product_id']) || !is_int($data['product_id'])) {
|
||||
throw new \InvalidArgumentException('Invalid response: missing or invalid product_id');
|
||||
}
|
||||
|
||||
$expiresAt = null;
|
||||
if (isset($data['expires_at']) && $data['expires_at'] !== null) {
|
||||
$expiresAt = new \DateTimeImmutable($data['expires_at']);
|
||||
try {
|
||||
$expiresAt = new \DateTimeImmutable($data['expires_at']);
|
||||
} catch (\Exception $e) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid response: invalid date format for expires_at',
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return new self(
|
||||
|
||||
@@ -26,14 +26,49 @@ final readonly class LicenseStatus
|
||||
|
||||
public static function fromArray(array $data): self
|
||||
{
|
||||
// Validate required fields
|
||||
if (!isset($data['valid']) || !is_bool($data['valid'])) {
|
||||
throw new \InvalidArgumentException('Invalid response: missing or invalid valid field');
|
||||
}
|
||||
if (!isset($data['status']) || !is_string($data['status'])) {
|
||||
throw new \InvalidArgumentException('Invalid response: missing or invalid status field');
|
||||
}
|
||||
if (!isset($data['domain']) || !is_string($data['domain'])) {
|
||||
throw new \InvalidArgumentException('Invalid response: missing or invalid domain field');
|
||||
}
|
||||
if (!isset($data['activations_count']) || !is_int($data['activations_count'])) {
|
||||
throw new \InvalidArgumentException('Invalid response: missing or invalid activations_count field');
|
||||
}
|
||||
if (!isset($data['max_activations']) || !is_int($data['max_activations'])) {
|
||||
throw new \InvalidArgumentException('Invalid response: missing or invalid max_activations field');
|
||||
}
|
||||
|
||||
$expiresAt = null;
|
||||
if (isset($data['expires_at']) && $data['expires_at'] !== null) {
|
||||
$expiresAt = new \DateTimeImmutable($data['expires_at']);
|
||||
try {
|
||||
$expiresAt = new \DateTimeImmutable($data['expires_at']);
|
||||
} catch (\Exception $e) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid response: invalid date format for expires_at',
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
$status = LicenseState::from($data['status']);
|
||||
} catch (\ValueError $e) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid response: unknown license status value',
|
||||
0,
|
||||
$e
|
||||
);
|
||||
}
|
||||
|
||||
return new self(
|
||||
valid: $data['valid'],
|
||||
status: LicenseState::from($data['status']),
|
||||
status: $status,
|
||||
domain: $data['domain'],
|
||||
expiresAt: $expiresAt,
|
||||
activationsCount: $data['activations_count'],
|
||||
|
||||
Reference in New Issue
Block a user