feat(cloudron): add tirreno package artifacts
- Add CloudronStack/output/CloudronPackages-Artifacts/tirreno/ directory and its contents - Includes package manifest, Dockerfile, source code, documentation, and build artifacts - Add tirreno-1761840148.tar.gz as a build artifact - Add tirreno-cloudron-package-1761841304.tar.gz as the Cloudron package - Include all necessary files for the tirreno Cloudron package This adds the complete tirreno Cloudron package artifacts to the repository.
This commit is contained in:
@@ -0,0 +1,215 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Tirreno ~ Open source user analytics
|
||||
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
|
||||
*
|
||||
* Licensed under GNU Affero General Public License version 3 of the or any later version.
|
||||
* For full copyright and license information, please see the LICENSE
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
|
||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
|
||||
* @link https://www.tirreno.com Tirreno(tm)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sensor\Factory;
|
||||
|
||||
use Sensor\Model\Enriched\EnrichedData;
|
||||
use Sensor\Model\Enriched\DomainEnriched;
|
||||
use Sensor\Model\Enriched\DomainNotFoundEnriched;
|
||||
use Sensor\Model\Enriched\DomainEnrichFailed;
|
||||
use Sensor\Model\Enriched\EmailEnriched;
|
||||
use Sensor\Model\Enriched\EmailEnrichFailed;
|
||||
use Sensor\Model\Enriched\IpAddressEnriched;
|
||||
use Sensor\Model\Enriched\IpAddressLocalhostEnriched;
|
||||
use Sensor\Model\Enriched\IpAddressEnrichFailed;
|
||||
use Sensor\Model\Enriched\IspEnriched;
|
||||
use Sensor\Model\Enriched\IspEnrichedEmpty;
|
||||
use Sensor\Model\Enriched\IspEnrichedLocalhost;
|
||||
use Sensor\Model\Enriched\PhoneEnriched;
|
||||
use Sensor\Model\Enriched\PhoneInvalidEnriched;
|
||||
use Sensor\Model\Enriched\PhoneEnrichFailed;
|
||||
use Sensor\Service\Enrichment\DataEnrichmentClientInterface;
|
||||
use Sensor\Service\Logger;
|
||||
|
||||
/**
|
||||
* @phpstan-import-type EnrichmentClientResponse from DataEnrichmentClientInterface
|
||||
*/
|
||||
class EnrichedDataFactory {
|
||||
private const IP_IS_BOGON_ERROR_TEXT = 'IP is bogon';
|
||||
private const VALIDATION_ERROR_TEXT = 'Validation failed';
|
||||
private const SERVER_ERROR = 'Server Error';
|
||||
|
||||
public function __construct(
|
||||
private Logger $logger,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @phpstan-param EnrichmentClientResponse $data
|
||||
*/
|
||||
public function createFromResponse(array $data, array $origin): EnrichedData {
|
||||
$email = null;
|
||||
if (isset($data['email']['email'])) {
|
||||
try {
|
||||
$earliestBreach = $data['email']['earliest_breach'] !== null ? new \DateTimeImmutable($data['email']['earliest_breach']) : null;
|
||||
$email = new EmailEnriched(
|
||||
$data['email']['email'],
|
||||
$data['email']['blockemails'],
|
||||
$data['email']['data_breach'],
|
||||
$data['email']['data_breaches'],
|
||||
$earliestBreach,
|
||||
$data['email']['profiles'],
|
||||
$data['email']['domain_contact_email'],
|
||||
$data['email']['alert_list'],
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->logWarning('Error during parsing email response', $e);
|
||||
}
|
||||
} elseif (isset($data['email']['value'])) {
|
||||
$email = new EmailEnrichFailed(
|
||||
$data['email']['error'] === self::SERVER_ERROR ? $origin['email'] : $data['email']['value'],
|
||||
$data['email']['error'] === self::VALIDATION_ERROR_TEXT, // checked must be true on validation error to prevent repeating requests
|
||||
);
|
||||
}
|
||||
|
||||
$domain = null;
|
||||
if (isset($data['domain']['domain']) && array_key_exists('ip', $data['domain'])) {
|
||||
try {
|
||||
$domain = new DomainEnriched(
|
||||
$data['domain']['domain'],
|
||||
$data['domain']['blockdomains'],
|
||||
$data['domain']['disposable_domains'],
|
||||
$data['domain']['free_email_provider'],
|
||||
$data['domain']['ip'],
|
||||
$data['domain']['geo_ip'],
|
||||
$data['domain']['geo_html'],
|
||||
$data['domain']['web_server'],
|
||||
$data['domain']['hostname'],
|
||||
$data['domain']['emails'],
|
||||
$data['domain']['phone'],
|
||||
$data['domain']['discovery_date'],
|
||||
$data['domain']['tranco_rank'],
|
||||
$data['domain']['creation_date'],
|
||||
$data['domain']['expiration_date'],
|
||||
$data['domain']['return_code'],
|
||||
$data['domain']['disabled'],
|
||||
$data['domain']['closest_snapshot'],
|
||||
$data['domain']['mx_record'],
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->logWarning('Error during parsing domain response', $e);
|
||||
}
|
||||
} elseif (isset($data['domain']['domain'])) {
|
||||
$domain = new DomainNotFoundEnriched(
|
||||
$data['domain']['domain'],
|
||||
$data['domain']['blockdomains'],
|
||||
$data['domain']['disposable_domains'],
|
||||
$data['domain']['free_email_provider'],
|
||||
$data['domain']['creation_date'],
|
||||
$data['domain']['expiration_date'],
|
||||
$data['domain']['return_code'],
|
||||
$data['domain']['disabled'],
|
||||
$data['domain']['closest_snapshot'],
|
||||
$data['domain']['mx_record'],
|
||||
);
|
||||
} elseif (isset($data['domain']['value'])) {
|
||||
$domain = new DomainEnrichFailed(
|
||||
$data['domain']['error'] === self::SERVER_ERROR ? $origin['domain'] : $data['domain']['value'],
|
||||
$data['domain']['error'] === self::VALIDATION_ERROR_TEXT, // checked must be true on validation error to prevent repeating requests
|
||||
);
|
||||
}
|
||||
|
||||
$ip = $isp = null;
|
||||
if (isset($data['ip']['ip'])) {
|
||||
try {
|
||||
$ip = new IpAddressEnriched(
|
||||
$data['ip']['ip'],
|
||||
$data['ip']['country'],
|
||||
$data['ip']['hosting'],
|
||||
$data['ip']['vpn'],
|
||||
$data['ip']['tor'],
|
||||
$data['ip']['relay'],
|
||||
$data['ip']['starlink'],
|
||||
$data['ip']['blocklist'],
|
||||
$data['ip']['domains_count'],
|
||||
$data['ip']['cidr'],
|
||||
$data['ip']['alert_list'],
|
||||
);
|
||||
|
||||
if (isset($data['ip']['asn'])) {
|
||||
$isp = new IspEnriched(
|
||||
$data['ip']['asn'],
|
||||
$data['ip']['name'],
|
||||
$data['ip']['description'],
|
||||
);
|
||||
} else {
|
||||
$isp = new IspEnrichedEmpty();
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->logWarning('Error during parsing IP response', $e);
|
||||
}
|
||||
} elseif (isset($data['ip']['error'])) {
|
||||
if ($data['ip']['error'] === self::IP_IS_BOGON_ERROR_TEXT) {
|
||||
$ip = new IpAddressLocalhostEnriched(
|
||||
$data['ip']['value'],
|
||||
);
|
||||
$isp = new IspEnrichedLocalhost();
|
||||
} else {
|
||||
$ip = new IpAddressEnrichFailed(
|
||||
$data['ip']['error'] === self::SERVER_ERROR ? $origin['ip'] : $data['ip']['value'],
|
||||
$data['ip']['error'] === self::VALIDATION_ERROR_TEXT, // checked must be true on validation error to prevent repeating requests
|
||||
);
|
||||
$isp = new IspEnrichedEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
$phone = null;
|
||||
if (isset($data['phone']['phone_number']) && isset($data['phone']['profiles'])) {
|
||||
try {
|
||||
$phone = new PhoneEnriched(
|
||||
$data['phone']['phone_number'],
|
||||
$data['phone']['profiles'],
|
||||
$data['phone']['iso_country_code'],
|
||||
$data['phone']['calling_country_code'],
|
||||
$data['phone']['national_format'],
|
||||
$data['phone']['invalid'],
|
||||
$data['phone']['validation_error'],
|
||||
$data['phone']['carrier_name'],
|
||||
$data['phone']['type'],
|
||||
$data['phone']['alert_list'],
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
$this->logger->logWarning('Error during parsing phone response', $e);
|
||||
}
|
||||
} elseif (isset($data['phone']['validation_error'])) {
|
||||
$this->logger->logWarning('Error getting phone from Enrichment API: ' . json_encode($data['phone']));
|
||||
$phone = new PhoneInvalidEnriched(
|
||||
$data['phone']['phone_number'],
|
||||
$data['phone']['invalid'],
|
||||
$data['phone']['validation_error'],
|
||||
);
|
||||
} elseif (isset($data['phone']['value'])) {
|
||||
$phone = new PhoneEnrichFailed(
|
||||
$data['phone']['error'] === self::SERVER_ERROR ? $origin['phone'] : $data['phone']['value'],
|
||||
$data['phone']['error'] === self::VALIDATION_ERROR_TEXT, // checked must be true on validation error to prevent repeating requests
|
||||
);
|
||||
}
|
||||
|
||||
// Check/log errors
|
||||
foreach ($data as $key => $value) {
|
||||
if (isset($value['error'])) {
|
||||
$this->logger->logWarning(sprintf(
|
||||
'Error getting %s from Enrichment API: %s',
|
||||
$key,
|
||||
json_encode($value),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return new EnrichedData($email, $domain, $ip, $isp, $phone, true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Tirreno ~ Open source user analytics
|
||||
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
|
||||
*
|
||||
* Licensed under GNU Affero General Public License version 3 of the or any later version.
|
||||
* For full copyright and license information, please see the LICENSE
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
|
||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
|
||||
* @link https://www.tirreno.com Tirreno(tm)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sensor\Factory;
|
||||
|
||||
use Sensor\Entity\DeviceEntity;
|
||||
use Sensor\Entity\DomainEnrichedEntity;
|
||||
use Sensor\Entity\DomainEntity;
|
||||
use Sensor\Entity\DomainNotFoundEntity;
|
||||
use Sensor\Entity\EmailEnrichedEntity;
|
||||
use Sensor\Entity\EmailEntity;
|
||||
use Sensor\Entity\EventEntity;
|
||||
use Sensor\Entity\IpAddressEnrichedEntity;
|
||||
use Sensor\Entity\IpAddressLocalhostEnrichedEntity;
|
||||
use Sensor\Entity\IpAddressEntity;
|
||||
use Sensor\Entity\CountryEntity;
|
||||
use Sensor\Entity\IspEntity;
|
||||
use Sensor\Entity\IspEnrichedEntity;
|
||||
use Sensor\Entity\IspLocalhostEntity;
|
||||
use Sensor\Entity\PhoneEnrichedEntity;
|
||||
use Sensor\Entity\PhoneEntity;
|
||||
use Sensor\Entity\PhoneInvalidEntity;
|
||||
use Sensor\Entity\RefererEntity;
|
||||
use Sensor\Entity\SessionEntity;
|
||||
use Sensor\Entity\UrlEntity;
|
||||
use Sensor\Entity\UrlQueryEntity;
|
||||
use Sensor\Entity\UserAgentEnrichedEntity;
|
||||
use Sensor\Entity\UserAgentEntity;
|
||||
use Sensor\Entity\PayloadEntity;
|
||||
use Sensor\Model\Blacklist\FraudDetected;
|
||||
use Sensor\Model\CreateEventDto;
|
||||
use Sensor\Model\DeviceDetected;
|
||||
use Sensor\Repository\CountryRepository;
|
||||
use Sensor\Model\Enriched\EnrichedData;
|
||||
use Sensor\Model\Enriched\IpAddressEnriched;
|
||||
use Sensor\Model\Enriched\IpAddressLocalhostEnriched;
|
||||
use Sensor\Model\Enriched\IpAddressEnrichFailed;
|
||||
use Sensor\Model\Enriched\PhoneEnriched;
|
||||
use Sensor\Model\Enriched\PhoneInvalidEnriched;
|
||||
use Sensor\Model\Enriched\PhoneEnrichFailed;
|
||||
use Sensor\Model\Enriched\DomainEnriched;
|
||||
use Sensor\Model\Enriched\DomainNotFoundEnriched;
|
||||
use Sensor\Model\Enriched\DomainEnrichFailed;
|
||||
use Sensor\Model\Enriched\EmailEnriched;
|
||||
use Sensor\Model\Enriched\EmailEnrichFailed;
|
||||
|
||||
class EventFactory {
|
||||
public function __construct(
|
||||
private CountryRepository $countryRepository,
|
||||
) {
|
||||
}
|
||||
|
||||
public function createFromDto(
|
||||
int $accountId,
|
||||
int $sessionId,
|
||||
int $apiKeyId,
|
||||
CreateEventDto $dto,
|
||||
?EnrichedData $enrichedData,
|
||||
FraudDetected $fraudDetected,
|
||||
?DeviceDetected $deviceDetected,
|
||||
?string $query,
|
||||
): EventEntity {
|
||||
$lastSeen = $dto->eventTime;
|
||||
|
||||
// Remove query from url
|
||||
$urlWithoutQuery = $query !== null ? str_replace($query, '', $dto->url) : $dto->url;
|
||||
|
||||
$queryEntity = null;
|
||||
if ($query !== null) {
|
||||
$queryEntity = new UrlQueryEntity($apiKeyId, $query, $lastSeen);
|
||||
}
|
||||
$url = new UrlEntity($apiKeyId, $urlWithoutQuery, $queryEntity, $dto->pageTitle, $dto->httpCode, $lastSeen);
|
||||
$eventType = $dto->eventType;
|
||||
$httpMethod = $dto->httpMethod;
|
||||
|
||||
if ($dto->httpReferer !== null) {
|
||||
$referer = new RefererEntity($apiKeyId, $dto->httpReferer, $lastSeen);
|
||||
}
|
||||
|
||||
$session = new SessionEntity($sessionId, $accountId, $apiKeyId, $lastSeen);
|
||||
|
||||
// set countryId after inserting ip
|
||||
$country = new CountryEntity($apiKeyId, 0, $lastSeen);
|
||||
|
||||
$ipAddress = null;
|
||||
if ($dto->ipAddress->localhost) {
|
||||
// sensor-defined localhost
|
||||
$isp = new IspLocalhostEntity($apiKeyId, $lastSeen);
|
||||
$ipAddress = new IpAddressLocalhostEnrichedEntity(
|
||||
$apiKeyId,
|
||||
$dto->ipAddress->value,
|
||||
$dto->ipAddress->hash,
|
||||
$fraudDetected->ip,
|
||||
$isp,
|
||||
$lastSeen,
|
||||
);
|
||||
} else {
|
||||
if ($enrichedData?->ip instanceof IpAddressEnriched || $enrichedData?->ip instanceof IpAddressLocalhostEnriched) {
|
||||
// isp IspEnriched or IspEnrichedEmpty
|
||||
// it's a new ip, checked is true; should be INSERTed or UPDATEd
|
||||
$countryId = $this->countryRepository->getCountryIdByCode($enrichedData->ip->countryCode);
|
||||
$isp = new IspEnrichedEntity(
|
||||
$apiKeyId,
|
||||
$enrichedData->isp->asn,
|
||||
$enrichedData->isp->name,
|
||||
$enrichedData->isp->description,
|
||||
$lastSeen,
|
||||
);
|
||||
$ipAddress = new IpAddressEnrichedEntity(
|
||||
$apiKeyId,
|
||||
$enrichedData->ip->ipAddress,
|
||||
$dto->ipAddress->hash,
|
||||
$countryId,
|
||||
$enrichedData->ip->hosting,
|
||||
$enrichedData->ip->vpn,
|
||||
$enrichedData->ip->tor,
|
||||
$enrichedData->ip->relay,
|
||||
$enrichedData->ip->starlink,
|
||||
$enrichedData->ip->blocklist,
|
||||
$enrichedData->ip->domainsCount,
|
||||
$enrichedData->ip->cidr,
|
||||
$enrichedData->ip->alertList,
|
||||
$fraudDetected->ip,
|
||||
$isp,
|
||||
true,
|
||||
$lastSeen,
|
||||
);
|
||||
} elseif ($enrichedData?->ip instanceof IpAddressEnrichFailed) {
|
||||
// checked can be false or true on bogon ip; should be INSERTed or UPDATEd (if it is reenrichment)
|
||||
// isp made of IspEnrichedLocalhost or IspEnrichedEmpty
|
||||
$isp = new IspEnrichedEntity(
|
||||
$apiKeyId,
|
||||
$enrichedData->isp->asn,
|
||||
$enrichedData->isp->name,
|
||||
$enrichedData->isp->description,
|
||||
$lastSeen,
|
||||
);
|
||||
$ipAddress = new IpAddressEntity(
|
||||
$apiKeyId,
|
||||
$enrichedData->ip->ipAddress,
|
||||
$dto->ipAddress->hash,
|
||||
$fraudDetected->ip,
|
||||
$isp,
|
||||
$enrichedData->ip->checked,
|
||||
$lastSeen,
|
||||
);
|
||||
} else {
|
||||
// ip already exists and has checked true or enrichment is off; should be UPDATEd or INSERTed if enrichment is off
|
||||
// isp unknown, N/A will be used if enrichment is off or failed
|
||||
$isp = new IspEntity(
|
||||
$apiKeyId,
|
||||
$lastSeen,
|
||||
);
|
||||
$ipAddress = new IpAddressEntity(
|
||||
$apiKeyId,
|
||||
$dto->ipAddress->value,
|
||||
$dto->ipAddress->hash,
|
||||
$fraudDetected->ip,
|
||||
$isp,
|
||||
null, // enrichment is off or was enriched earlier
|
||||
$lastSeen,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$domain = null;
|
||||
if ($dto->emailDomain !== null) {
|
||||
if ($enrichedData?->domain instanceof DomainEnriched) {
|
||||
$domain = new DomainEnrichedEntity(
|
||||
$apiKeyId,
|
||||
$enrichedData->domain->domain,
|
||||
$enrichedData->domain->blockdomains,
|
||||
$enrichedData->domain->disposableDomains,
|
||||
$enrichedData->domain->freeEmailProvider,
|
||||
$enrichedData->domain->ip,
|
||||
$enrichedData->domain->geoIp,
|
||||
$enrichedData->domain->geoHtml,
|
||||
$enrichedData->domain->webServer,
|
||||
$enrichedData->domain->hostname,
|
||||
$enrichedData->domain->emails,
|
||||
$enrichedData->domain->phone,
|
||||
$enrichedData->domain->discoveryDate,
|
||||
$enrichedData->domain->trancoRank,
|
||||
$enrichedData->domain->creationDate,
|
||||
$enrichedData->domain->expirationDate,
|
||||
$enrichedData->domain->returnCode,
|
||||
$enrichedData->domain->disabled,
|
||||
$enrichedData->domain->closestSnapshot,
|
||||
$enrichedData->domain->mxRecord,
|
||||
true,
|
||||
$lastSeen,
|
||||
);
|
||||
} elseif ($enrichedData?->domain instanceof DomainNotFoundEnriched) {
|
||||
$domain = new DomainNotFoundEntity(
|
||||
$apiKeyId,
|
||||
$enrichedData->domain->domain,
|
||||
$enrichedData->domain->blockdomains,
|
||||
$enrichedData->domain->disposableDomains,
|
||||
$enrichedData->domain->freeEmailProvider,
|
||||
$enrichedData->domain->creationDate,
|
||||
$enrichedData->domain->expirationDate,
|
||||
$enrichedData->domain->returnCode,
|
||||
$enrichedData->domain->disabled,
|
||||
$enrichedData->domain->closestSnapshot,
|
||||
$enrichedData->domain->mxRecord,
|
||||
true,
|
||||
$lastSeen,
|
||||
);
|
||||
} elseif ($enrichedData?->domain instanceof DomainEnrichFailed) {
|
||||
$domain = new DomainEntity(
|
||||
$apiKeyId,
|
||||
$enrichedData->domain->domain,
|
||||
$enrichedData->domain->checked,
|
||||
$lastSeen,
|
||||
);
|
||||
} else {
|
||||
$domain = new DomainEntity(
|
||||
$apiKeyId,
|
||||
$dto->emailDomain,
|
||||
null, // enrichment is off or was enriched earlier
|
||||
$lastSeen,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$email = null;
|
||||
if ($dto->emailAddress !== null && $domain !== null) {
|
||||
if ($enrichedData?->email instanceof EmailEnriched) {
|
||||
$email = new EmailEnrichedEntity(
|
||||
$accountId,
|
||||
$apiKeyId,
|
||||
$enrichedData->email->email,
|
||||
$dto->emailAddress->hash,
|
||||
$domain,
|
||||
$enrichedData->email->blockEmails,
|
||||
$enrichedData->email->dataBreach,
|
||||
$enrichedData->email->dataBreaches,
|
||||
$enrichedData->email->earliestBreach,
|
||||
$enrichedData->email->profiles,
|
||||
$enrichedData->email->domainContactEmail,
|
||||
$enrichedData->email->alertList,
|
||||
$fraudDetected->email,
|
||||
true,
|
||||
$lastSeen,
|
||||
);
|
||||
} elseif ($enrichedData?->email instanceof EmailEnrichFailed) {
|
||||
$email = new EmailEntity(
|
||||
$accountId,
|
||||
$apiKeyId,
|
||||
$enrichedData->email->email,
|
||||
$dto->emailAddress->hash,
|
||||
$domain,
|
||||
$fraudDetected->email,
|
||||
$enrichedData->email->checked,
|
||||
$lastSeen,
|
||||
);
|
||||
} else {
|
||||
$email = new EmailEntity(
|
||||
$accountId,
|
||||
$apiKeyId,
|
||||
$dto->emailAddress->value,
|
||||
$dto->emailAddress->hash,
|
||||
$domain,
|
||||
$fraudDetected->email,
|
||||
null, // enrichment is off or was enriched earlier
|
||||
$lastSeen,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$phone = null;
|
||||
if ($dto->phoneNumber !== null) {
|
||||
$countryId = 0;
|
||||
if ($enrichedData?->phone instanceof PhoneEnriched) {
|
||||
if ($enrichedData->phone->countryCode !== null) {
|
||||
$countryId = $this->countryRepository->getCountryIdByCode($enrichedData->phone->countryCode);
|
||||
}
|
||||
$phone = new PhoneEnrichedEntity(
|
||||
$accountId,
|
||||
$apiKeyId,
|
||||
$enrichedData->phone->phoneNumber,
|
||||
$dto->phoneNumber->hash,
|
||||
$enrichedData->phone->profiles,
|
||||
$countryId,
|
||||
$enrichedData->phone->callingCountryCode,
|
||||
$enrichedData->phone->nationalFormat,
|
||||
$enrichedData->phone->invalid,
|
||||
$enrichedData->phone->validationErrors,
|
||||
$enrichedData->phone->carrierName,
|
||||
$enrichedData->phone->type,
|
||||
$enrichedData->phone->alertList,
|
||||
$fraudDetected->phone,
|
||||
true,
|
||||
$lastSeen,
|
||||
);
|
||||
} elseif ($enrichedData?->phone instanceof PhoneInvalidEnriched) {
|
||||
$phone = new PhoneInvalidEntity(
|
||||
$accountId,
|
||||
$apiKeyId,
|
||||
$enrichedData->phone->phoneNumber,
|
||||
$dto->phoneNumber->hash,
|
||||
$countryId,
|
||||
$fraudDetected->phone,
|
||||
$enrichedData->phone->validationErrors,
|
||||
true,
|
||||
$lastSeen,
|
||||
);
|
||||
} elseif ($enrichedData?->phone instanceof PhoneEnrichFailed) {
|
||||
$phone = new PhoneEntity(
|
||||
$accountId,
|
||||
$apiKeyId,
|
||||
$enrichedData->phone->phoneNumber,
|
||||
$dto->phoneNumber->hash,
|
||||
$countryId,
|
||||
$fraudDetected->phone,
|
||||
$enrichedData->phone->checked,
|
||||
$lastSeen,
|
||||
);
|
||||
} else {
|
||||
$phone = new PhoneEntity(
|
||||
$accountId,
|
||||
$apiKeyId,
|
||||
$dto->phoneNumber->value,
|
||||
$dto->phoneNumber->hash,
|
||||
$countryId, // set country to 0 if enrichment is off or keep existing country in query
|
||||
$fraudDetected->phone,
|
||||
null, // enrichment is off or was enriched earlier
|
||||
$lastSeen,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$userAgent = null;
|
||||
if ($deviceDetected instanceof DeviceDetected) {
|
||||
$userAgent = new UserAgentEnrichedEntity(
|
||||
$apiKeyId,
|
||||
$deviceDetected->userAgent,
|
||||
$deviceDetected->device,
|
||||
$deviceDetected->browserName,
|
||||
$deviceDetected->browserVersion,
|
||||
$deviceDetected->osName,
|
||||
$deviceDetected->osVersion,
|
||||
$deviceDetected->modified,
|
||||
true,
|
||||
$lastSeen,
|
||||
);
|
||||
} else {
|
||||
$userAgent = new UserAgentEntity(
|
||||
$apiKeyId,
|
||||
$dto->userAgent,
|
||||
null, // ua is null, was enriched earlier or enrichment is off
|
||||
$lastSeen,
|
||||
);
|
||||
}
|
||||
|
||||
$device = new DeviceEntity($accountId, $apiKeyId, $userAgent, $dto->browserLanguage, $lastSeen);
|
||||
|
||||
$payload = ($dto->payload) ? (new PayloadEntity($accountId, $apiKeyId, $dto->payload, $lastSeen)) : null;
|
||||
|
||||
return new EventEntity(
|
||||
$accountId,
|
||||
$session,
|
||||
$apiKeyId,
|
||||
$ipAddress,
|
||||
$url,
|
||||
$eventType,
|
||||
$httpMethod,
|
||||
$device,
|
||||
$referer ?? null,
|
||||
$email ?? null,
|
||||
$phone ?? null,
|
||||
$dto->httpCode,
|
||||
$dto->eventTime,
|
||||
$dto->traceId,
|
||||
$payload,
|
||||
$country,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Tirreno ~ Open source user analytics
|
||||
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
|
||||
*
|
||||
* Licensed under GNU Affero General Public License version 3 of the or any later version.
|
||||
* For full copyright and license information, please see the LICENSE
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
|
||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
|
||||
* @link https://www.tirreno.com Tirreno(tm)
|
||||
*/
|
||||
|
||||
namespace Sensor\Factory;
|
||||
|
||||
use Sensor\Entity\LogbookEntity;
|
||||
use Sensor\Model\Http\ErrorResponse;
|
||||
use Sensor\Model\Http\RegularResponse;
|
||||
use Sensor\Model\Http\Request;
|
||||
use Sensor\Model\Http\ValidationFailedResponse;
|
||||
use Sensor\Repository\ApiKeyRepository;
|
||||
|
||||
class LogbookEntityFactory {
|
||||
public function create(
|
||||
int $apiKeyId,
|
||||
\DateTime $startedTime,
|
||||
RegularResponse|ErrorResponse $response,
|
||||
): LogbookEntity {
|
||||
$eventId = null;
|
||||
if ($response instanceof RegularResponse) {
|
||||
$errorText = $response->validationErrors();
|
||||
$errorType = $errorText !== null
|
||||
? LogbookEntity::ERROR_TYPE_VALIDATION_ERROR
|
||||
: LogbookEntity::ERROR_TYPE_SUCCESS
|
||||
;
|
||||
$eventId = $response->eventId;
|
||||
} elseif ($response instanceof ValidationFailedResponse) {
|
||||
$errorType = LogbookEntity::ERROR_TYPE_CRITICAL_VALIDATION_ERROR;
|
||||
$errorText = json_encode([$response->jsonSerialize()]);
|
||||
} elseif ($response instanceof ErrorResponse) {
|
||||
$errorType = LogbookEntity::ERROR_TYPE_CRITICAL_ERROR;
|
||||
$errorText = json_encode([$response->jsonSerialize()]);
|
||||
} else {
|
||||
$errorType = LogbookEntity::ERROR_TYPE_CRITICAL_ERROR;
|
||||
$errorText = json_encode(['Undefined error']);
|
||||
}
|
||||
|
||||
return new LogbookEntity(
|
||||
$apiKeyId,
|
||||
$_SERVER['REMOTE_ADDR'],
|
||||
$eventId,
|
||||
$errorType,
|
||||
$errorText,
|
||||
$this->getRawRequest(),
|
||||
$this->formatStarted($startedTime),
|
||||
);
|
||||
}
|
||||
|
||||
public function createFromException(
|
||||
int $apiKeyId,
|
||||
\DateTime $startedTime,
|
||||
string $errorText,
|
||||
): LogbookEntity {
|
||||
return new LogbookEntity(
|
||||
$apiKeyId,
|
||||
$_SERVER['REMOTE_ADDR'],
|
||||
null,
|
||||
3,
|
||||
$errorText,
|
||||
$this->getRawRequest(),
|
||||
$this->formatStarted($startedTime),
|
||||
);
|
||||
}
|
||||
|
||||
private function getRawRequest(): string {
|
||||
return json_encode(array_intersect_key($_POST, array_flip(Request::ACCEPTABLE_FIELDS)));
|
||||
}
|
||||
|
||||
private function formatStarted(\DateTime $startedTime): string {
|
||||
$milliseconds = (int) ($startedTime->format('u') / 1000);
|
||||
|
||||
return $startedTime->format('Y-m-d H:i:s') . '.' . sprintf('%03d', $milliseconds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Tirreno ~ Open source user analytics
|
||||
* Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
|
||||
*
|
||||
* Licensed under GNU Affero General Public License version 3 of the or any later version.
|
||||
* For full copyright and license information, please see the LICENSE
|
||||
* Redistributions of files must retain the above copyright notice.
|
||||
*
|
||||
* @copyright Copyright (c) Tirreno Technologies Sàrl (https://www.tirreno.com)
|
||||
* @license https://opensource.org/licenses/AGPL-3.0 AGPL License
|
||||
* @link https://www.tirreno.com Tirreno(tm)
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sensor\Factory;
|
||||
|
||||
use Sensor\Exception\ValidationException;
|
||||
use Sensor\Model\CreateEventDto;
|
||||
use Sensor\Model\HashedValue;
|
||||
use Sensor\Model\Validated\Email;
|
||||
use Sensor\Model\Validated\IpAddress;
|
||||
use Sensor\Model\Validated\Phone;
|
||||
use Sensor\Model\Validated\Timestamp;
|
||||
use Sensor\Model\Validated\HttpCode;
|
||||
use Sensor\Model\Validated\Firstname;
|
||||
use Sensor\Model\Validated\Lastname;
|
||||
use Sensor\Model\Validated\Fullname;
|
||||
use Sensor\Model\Validated\HttpReferer;
|
||||
use Sensor\Model\Validated\Userid;
|
||||
use Sensor\Model\Validated\PageTitle;
|
||||
use Sensor\Model\Validated\Url;
|
||||
use Sensor\Model\Validated\UserAgent;
|
||||
use Sensor\Model\Validated\BrowserLanguage;
|
||||
use Sensor\Model\Validated\EventType;
|
||||
use Sensor\Model\Validated\HttpMethod;
|
||||
use Sensor\Model\Validated\UserCreated;
|
||||
use Sensor\Model\Validated\Payloads\FieldEditPayload;
|
||||
use Sensor\Model\Validated\Payloads\PageSearchPayload;
|
||||
use Sensor\Model\Validated\Payloads\EmailChangePayload;
|
||||
use Sensor\Repository\EventRepository;
|
||||
use Sensor\Service\Constants;
|
||||
|
||||
class RequestFactory {
|
||||
private const REQUIRED_FIELDS = ['ipAddress', 'url', 'eventTime'];
|
||||
|
||||
/**
|
||||
* @param array<string, string> $data
|
||||
*/
|
||||
public static function createFromArray(array $data, ?string $traceId, EventRepository $eventRepository): CreateEventDto {
|
||||
foreach (self::REQUIRED_FIELDS as $key) {
|
||||
if (!isset($data[$key])) {
|
||||
throw new ValidationException('Required field is missing or empty', $key);
|
||||
}
|
||||
}
|
||||
|
||||
$eventTime = new Timestamp($data['eventTime']);
|
||||
|
||||
$userCreated = isset($data['userCreated']) ? (new UserCreated($data['userCreated'])) : null;
|
||||
|
||||
$referer = isset($data['httpReferer']) ? (new HttpReferer($data['httpReferer'])) : null;
|
||||
$httpCode = isset($data['httpCode']) ? (new HttpCode($data['httpCode'])) : null;
|
||||
|
||||
$ipAddress = new IpAddress($data['ipAddress']);
|
||||
|
||||
$phone = isset($data['phoneNumber']) ? (new Phone($data['phoneNumber'])) : null;
|
||||
|
||||
$email = isset($data['emailAddress']) ? (new Email($data['emailAddress'])) : null;
|
||||
$firstname = isset($data['firstName']) ? (new Firstname($data['firstName'])) : null;
|
||||
$lastname = isset($data['lastName']) ? (new Lastname($data['lastName'])) : null;
|
||||
$fullname = isset($data['fullName']) ? (new Fullname($data['fullName'])) : null;
|
||||
$username = isset($data['userName']) ? (new Userid($data['userName'])) : null;
|
||||
$pageTitle = isset($data['pageTitle']) ? (new PageTitle($data['pageTitle'])) : null;
|
||||
$url = isset($data['url']) ? (new Url($data['url'])) : null;
|
||||
$userAgent = isset($data['userAgent']) ? (new UserAgent($data['userAgent'])) : null;
|
||||
$browserLang = isset($data['browserLanguage']) ? (new BrowserLanguage($data['browserLanguage'])) : null;
|
||||
$eventType = isset($data['eventType']) ? (new EventType($data['eventType'])) : null;
|
||||
$httpMethod = isset($data['httpMethod']) ? (new HttpMethod($data['httpMethod'])) : null;
|
||||
|
||||
$payload = null;
|
||||
$payloadRaw = $data['payload'] ?? null;
|
||||
|
||||
if ($eventType?->value) {
|
||||
$eventTypeId = $eventRepository->getEventType($eventType->value);
|
||||
|
||||
if ($eventTypeId === Constants::FIELD_EDIT_EVENT_TYPE_ID) {
|
||||
$payload = new FieldEditPayload($payloadRaw);
|
||||
} elseif ($payloadRaw) {
|
||||
switch ($eventTypeId) {
|
||||
case Constants::ACCOUNT_EMAIL_CHANGE_EVENT_TYPE_ID:
|
||||
$payload = new EmailChangePayload($payloadRaw);
|
||||
break;
|
||||
case Constants::PAGE_SEARCH_EVENT_TYPE_ID:
|
||||
$payload = new PageSearchPayload($payloadRaw);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$validatedParams = [
|
||||
$email, $eventTime, $userCreated, $referer, $httpCode, $ipAddress,
|
||||
$phone, $firstname, $lastname, $fullname, $username, $pageTitle,
|
||||
$url, $userAgent, $browserLang, $eventType, $httpMethod, $payload,
|
||||
];
|
||||
|
||||
$changedParams = self::changedParams($validatedParams);
|
||||
|
||||
//$email = !isset($data['emailAddress']) && !isset($data['userName']) ? Email::makePlaceholder() : $email;
|
||||
//$username = $username === null ? md5($email->value) : $username->value;
|
||||
|
||||
if ($email === null && $username === null) {
|
||||
$username = 'N/A';
|
||||
} else {
|
||||
$username = $username === null ? md5($email->value) : $username->value;
|
||||
}
|
||||
|
||||
return new CreateEventDto(
|
||||
$firstname?->value,
|
||||
$lastname?->value,
|
||||
$fullname?->value,
|
||||
$pageTitle?->value,
|
||||
$username,
|
||||
$email !== null ? new HashedValue($email) : null,
|
||||
$email !== null ? explode('@', $email->value)[1] : null,
|
||||
$phone !== null && !$phone->isEmpty() ? new HashedValue($phone) : null,
|
||||
new HashedValue($ipAddress),
|
||||
$url?->value,
|
||||
$userAgent?->value,
|
||||
$eventTime->value,
|
||||
$referer?->value,
|
||||
$httpCode?->value,
|
||||
$browserLang?->value,
|
||||
$eventType?->value,
|
||||
$httpMethod?->value,
|
||||
$userCreated?->value,
|
||||
$traceId,
|
||||
$payload?->value,
|
||||
$changedParams,
|
||||
);
|
||||
}
|
||||
|
||||
private static function changedParams(array $validatedParams): array {
|
||||
$result = [];
|
||||
|
||||
foreach ($validatedParams as $param) {
|
||||
if ($param !== null) {
|
||||
$validation = $param->validationStatement();
|
||||
if ($validation !== null) {
|
||||
$result[] = $validation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
//
|
||||
Reference in New Issue
Block a user