- 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.
		
			
				
	
	
		
			253 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			253 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?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 Controllers\Admin\Enrichment;
 | 
						|
 | 
						|
class Data extends \Controllers\Base {
 | 
						|
    public function enrichEntity(string $type, ?string $search, ?int $entityId, int $apiKey, ?string $enrichmentKey): array {
 | 
						|
        if ($enrichmentKey === null) {
 | 
						|
            return ['ERROR_CODE' => \Utils\ErrorCodes::ENRICHMENT_API_KEY_DOES_NOT_EXIST];
 | 
						|
        }
 | 
						|
        set_error_handler([\Utils\ErrorHandler::class, 'exceptionErrorHandler']);
 | 
						|
        $search = $search !== null ? ['value' => $search] : null;
 | 
						|
        $result = $this->enrichEntityProcess($type, $search, $entityId, $apiKey, $enrichmentKey);
 | 
						|
        restore_error_handler();
 | 
						|
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
 | 
						|
    private function enrichEntityProcess(string $type, ?array $search, ?int $entityId, int $apiKey, ?string $enrichmentKey): array {
 | 
						|
        $processErrorMessage = ['ERROR_CODE' => \Utils\ErrorCodes::ENRICHMENT_API_UNKNOWN_ERROR];
 | 
						|
 | 
						|
        if ($type === 'device') {
 | 
						|
            if ($entityId !== null) {
 | 
						|
                $model = new \Models\Device();
 | 
						|
                $device = $model->getFullDeviceInfoById($entityId, $apiKey);
 | 
						|
                if ($device !== []) {
 | 
						|
                    $entityId = $device['ua_id'];
 | 
						|
                    $type = 'ua';
 | 
						|
                } else {
 | 
						|
                    return $processErrorMessage;
 | 
						|
                }
 | 
						|
            } else {
 | 
						|
                return $processErrorMessage;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        $model = new \Models\ApiKeys();
 | 
						|
        $attributes = $model->enrichableAttributes($apiKey);
 | 
						|
 | 
						|
        if (!array_key_exists($type, $attributes)) {
 | 
						|
            return ['ERROR_CODE' => \Utils\ErrorCodes::ENRICHMENT_API_ATTRIBUTE_IS_UNAVAILABLE];
 | 
						|
        }
 | 
						|
 | 
						|
        $modelDb = null;
 | 
						|
        $modelResult = null;
 | 
						|
        $extraModel = null;
 | 
						|
        switch ($type) {
 | 
						|
            case 'ip':
 | 
						|
                $modelDb        = new \Models\Ip();
 | 
						|
                $modelResult    = new \Models\Enrichment\Ip();
 | 
						|
                $extraModel     = new \Models\Enrichment\LocalhostIp();
 | 
						|
                break;
 | 
						|
            case 'email':
 | 
						|
                $modelDb        = new \Models\Email();
 | 
						|
                $modelResult    = new \Models\Enrichment\Email();
 | 
						|
                break;
 | 
						|
            case 'domain':
 | 
						|
                $modelDb        = new \Models\Domain();
 | 
						|
                $modelResult    = new \Models\Enrichment\DomainFound();
 | 
						|
                $extraModel     = new \Models\Enrichment\DomainNotFound();
 | 
						|
                break;
 | 
						|
            case 'phone':
 | 
						|
                $modelDb        = new \Models\Phone();
 | 
						|
                $modelResult    = new \Models\Enrichment\PhoneValid();
 | 
						|
                $extraModel     = new \Models\Enrichment\PhoneInvalid();
 | 
						|
                break;
 | 
						|
            case 'ua':
 | 
						|
                $modelDb        = new \Models\Device();
 | 
						|
                $modelResult    = new \Models\Enrichment\Device();
 | 
						|
                break;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($modelDb === null) {
 | 
						|
            return $processErrorMessage;
 | 
						|
        }
 | 
						|
 | 
						|
        $value = $entityId !== null ? $modelDb->extractById($entityId, $apiKey) : $search;
 | 
						|
 | 
						|
        if ($value === null || $value === []) {
 | 
						|
            return $processErrorMessage;
 | 
						|
        }
 | 
						|
 | 
						|
        $apiError = null;
 | 
						|
 | 
						|
        try {
 | 
						|
            [$statusCode, $response,] = $this->enrichEntityByValue($type, $value, $enrichmentKey);
 | 
						|
            $error = \Utils\ApiResponseFormats::getErrorResponseFormat();
 | 
						|
            $apiError = \Utils\ApiResponseFormats::matchResponse($response[$type] ?? [], $error) ? $response[$type]['error'] : null;
 | 
						|
        } catch (\ErrorException $e) {
 | 
						|
            return $processErrorMessage;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($statusCode === 403) {
 | 
						|
            return ['ERROR_CODE' => \Utils\ErrorCodes::ENRICHMENT_API_KEY_OVERUSE];
 | 
						|
        }
 | 
						|
 | 
						|
        if ($type === 'ip') {
 | 
						|
            // do not raise on bogon ip
 | 
						|
            if ($apiError === \Utils\Constants::get('ENRICHMENT_IP_IS_NOT_FOUND')) {
 | 
						|
                return ['ERROR_CODE' => \Utils\ErrorCodes::ENRICHMENT_API_IP_NOT_FOUND];
 | 
						|
            } elseif ($apiError !== null && $apiError !== \Utils\Constants::get('ENRICHMENT_IP_IS_BOGON') || $statusCode !== 200 || $response[$type] === null) {
 | 
						|
                return $processErrorMessage;
 | 
						|
            }
 | 
						|
        } elseif ($apiError !== null || $statusCode !== 200 || $response[$type] === null) {
 | 
						|
            return $processErrorMessage;
 | 
						|
        }
 | 
						|
 | 
						|
        try {
 | 
						|
            $modelResult->init($response[$type]);
 | 
						|
        } catch (\ErrorException $e) {
 | 
						|
            if ($extraModel === null) {
 | 
						|
                return $processErrorMessage;
 | 
						|
            }
 | 
						|
            try {
 | 
						|
                $extraModel->init($response[$type]);
 | 
						|
                $modelResult = $extraModel;
 | 
						|
            } catch (\ErrorException $e) {
 | 
						|
                return $processErrorMessage;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        // change value in db only if $entityId was passed
 | 
						|
        if ($entityId !== null) {
 | 
						|
            try {
 | 
						|
                $modelResult->updateEntityInDb($entityId, $apiKey);
 | 
						|
            } catch (\ErrorException $e) {
 | 
						|
                return $processErrorMessage;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return [
 | 
						|
            $type             => $response[$type],
 | 
						|
            'SUCCESS_MESSAGE' => $this->f3->get('AdminEnrichment_success_message'),
 | 
						|
        ];
 | 
						|
    }
 | 
						|
 | 
						|
    private function validateResponse(string $requestType, int $statusCode, ?array $result, string $errorMessage): bool|string|int {
 | 
						|
        if (!is_array($result)) {
 | 
						|
            return \Utils\ErrorCodes::ENRICHMENT_API_UNKNOWN_ERROR;
 | 
						|
        }
 | 
						|
 | 
						|
        if ($statusCode === 200 && is_array($result) && is_array($result[$requestType])) {
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        $details = $result['detail'] ?? null;
 | 
						|
        if ($details) {
 | 
						|
            if (is_array($details)) {
 | 
						|
                $messages = array_map(function ($detail) {
 | 
						|
                    if (isset($detail['msg']) && $detail['msg'] !== null && $detail['msg'] !== '') {
 | 
						|
                        return $detail['msg'];
 | 
						|
                    }
 | 
						|
                }, $details);
 | 
						|
                $messages = implode('; ', $messages);
 | 
						|
            } else {
 | 
						|
                $messages = $details;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        if (strlen($errorMessage) > 0) {
 | 
						|
            \Utils\Logger::log('Enrichment API web error', $errorMessage);
 | 
						|
        }
 | 
						|
 | 
						|
        if (!isset($messages) || strlen($messages) < 1) {
 | 
						|
            return \Utils\ErrorCodes::ENRICHMENT_API_UNKNOWN_ERROR;
 | 
						|
        }
 | 
						|
 | 
						|
        return $messages;
 | 
						|
    }
 | 
						|
 | 
						|
    private function enrichEntityByValue(string $type, array $value, string $enrichmentKey): array {
 | 
						|
        $apiUrl = \Utils\Variables::getEnrichtmentApi();
 | 
						|
        $postFields = [
 | 
						|
            $type => $value['value'],
 | 
						|
        ];
 | 
						|
 | 
						|
        $options = [
 | 
						|
            'method' => 'POST',
 | 
						|
            'header' => [
 | 
						|
                'Content-Type: application/json',
 | 
						|
                'Authorization: Bearer ' . $enrichmentKey,
 | 
						|
                'User-Agent: ' . $this->f3->get('USER_AGENT'),
 | 
						|
            ],
 | 
						|
            'content' => \json_encode($postFields),
 | 
						|
        ];
 | 
						|
 | 
						|
        /** @var array{request: array<string>, body: string, headers: array<string>, engine: string, cached: bool, error: string} $result */
 | 
						|
        $result = \Web::instance()->request(
 | 
						|
            url: sprintf('%s/query', $apiUrl),
 | 
						|
            options: $options,
 | 
						|
        );
 | 
						|
 | 
						|
        $matches = [];
 | 
						|
        preg_match('/^HTTP\/(\d+)(?:\.\d)? (\d{3})/', $result['headers'][0], $matches);
 | 
						|
 | 
						|
        $jsonResponse = json_decode($result['body'], true);
 | 
						|
        $statusCode = (int) ($matches[2] ?? 0);
 | 
						|
 | 
						|
        $errorMessages = $this->validateResponse($type, $statusCode, $jsonResponse, $result['error']);
 | 
						|
 | 
						|
        return [$statusCode, $jsonResponse, $errorMessages];
 | 
						|
    }
 | 
						|
 | 
						|
    public function getNotCheckedEntitiesCount(int $apiKey): array {
 | 
						|
        $model = new \Models\ApiKeys();
 | 
						|
        $models = $model->enrichableAttributes($apiKey);
 | 
						|
        $result = [];
 | 
						|
 | 
						|
        foreach ($models as $type => $model) {
 | 
						|
            $result[$type] = (new $model())->countNotChecked($apiKey);
 | 
						|
        }
 | 
						|
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
 | 
						|
    public function getNotCheckedExists(int $apiKey): bool {
 | 
						|
        $model = new \Models\ApiKeys();
 | 
						|
        $models = $model->enrichableAttributes($apiKey);
 | 
						|
 | 
						|
        foreach ($models as $model) {
 | 
						|
            if ((new $model())->notCheckedExists($apiKey)) {
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    public function getNotCheckedEntitiesByUserId(int $userId, int $apiKey): array {
 | 
						|
        $model = new \Models\ApiKeys();
 | 
						|
        $models = $model->enrichableAttributes($apiKey);
 | 
						|
        $result = [];
 | 
						|
 | 
						|
        foreach ($models as $type => $model) {
 | 
						|
            $result[$type] = (new $model())->notCheckedForUserId($userId, $apiKey);
 | 
						|
        }
 | 
						|
 | 
						|
        return $result;
 | 
						|
    }
 | 
						|
}
 |