<?php declare(strict_types=1); /** * @copyright 2020 Ad Aures * @license https://www.gnu.org/licenses/agpl-3.0.en.html AGPL3 * @link https://castopod.org/ */ namespace Modules\Analytics\Controllers; use App\Entities\Episode; use App\Models\EpisodeModel; use CodeIgniter\Controller; use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\HTTP\RedirectResponse; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; use Config\Services; use Modules\Analytics\Config\Analytics; use Modules\PremiumPodcasts\Models\SubscriptionModel; use Psr\Log\LoggerInterface; class EpisodeAnalyticsController extends Controller { /** * An array of helpers to be loaded automatically upon class instantiation. These helpers will be available to all * other controllers that extend Analytics. * * @var string[] */ protected $helpers = ['analytics']; protected Analytics $config; /** * Constructor. */ public function initController( RequestInterface $request, ResponseInterface $response, LoggerInterface $logger ): void { // Do Not Edit This Line parent::initController($request, $response, $logger); set_user_session_deny_list_ip(); set_user_session_location(); set_user_session_player(); $this->config = config('Analytics'); } public function hit(string $base64EpisodeData, string ...$audioPath): RedirectResponse|ResponseInterface { $session = Services::session(); $session->start(); $serviceName = ''; if ($this->request->getGet('_from')) { $serviceName = $this->request->getGet('_from'); } elseif ($session->get('embed_domain') !== null) { $serviceName = $session->get('embed_domain'); } elseif ($session->get('referer') !== null && $session->get('referer') !== '- Direct -') { $serviceName = parse_url($session->get('referer'), PHP_URL_HOST); } $episodeData = unpack( 'IpodcastId/IepisodeId/IbytesThreshold/IfileSize/Iduration/IpublicationDate', base64_url_decode($base64EpisodeData), ); if (! $episodeData) { throw PageNotFoundException::forPageNotFound(); } // check if episode is premium? $episode = (new EpisodeModel())->getEpisodeById($episodeData['episodeId']); if (! $episode instanceof Episode) { return $this->response->setStatusCode(404); } $subscription = null; // check if podcast is already unlocked before any token validation if ($episode->is_premium && ($subscription = service('premium_podcasts')->subscription( $episode->podcast->handle )) === null) { // look for token as GET parameter if (($token = $this->request->getGet('token')) === null) { return $this->response->setStatusCode( 401, 'Episode is premium, you must provide a token to unlock it.' ); } // check if there's a valid subscription for the provided token if (($subscription = (new SubscriptionModel())->validateSubscription( $episode->podcast->handle, $token )) === null) { return $this->response->setStatusCode(401, 'Invalid token!'); } } podcast_hit( $episodeData['podcastId'], $episodeData['episodeId'], $episodeData['bytesThreshold'], $episodeData['fileSize'], $episodeData['duration'], $episodeData['publicationDate'], $serviceName, $subscription !== null ? $subscription->id : null ); return redirect()->to($this->config->getAudioUrl($episode->audio->file_path)); } }