%PDF- %PDF-
Direktori : /www/varak.net/nextcloud.varak.net/apps_old/apps/cospend/lib/Controller/ |
Current File : //www/varak.net/nextcloud.varak.net/apps_old/apps/cospend/lib/Controller/PageController.php |
<?php /** * Nextcloud - cospend * * This file is licensed under the Affero General Public License version 3 or * later. See the COPYING file. * * @author Julien Veyssier <eneiluj@posteo.net> * @copyright Julien Veyssier 2019 */ namespace OCA\Cospend\Controller; use OC\Files\Filesystem; use OCA\Cospend\AppInfo\Application; use OCA\Cospend\Service\ProjectService; use OCP\App\AppPathNotFoundException; use OCP\App\IAppManager; use OCP\AppFramework\Controller; use OCP\AppFramework\Http; use OCP\AppFramework\Http\Attribute\BruteForceProtection; use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\Attribute\NoCSRFRequired; use OCP\AppFramework\Http\Attribute\OpenAPI; use OCP\AppFramework\Http\Attribute\PublicPage; use OCP\AppFramework\Http\ContentSecurityPolicy; use OCP\AppFramework\Http\DataDisplayResponse; use OCP\AppFramework\Http\NotFoundResponse; use OCP\AppFramework\Http\Response; use OCP\AppFramework\Http\Template\PublicTemplateResponse; use OCP\AppFramework\Http\TemplateResponse; use OCP\AppFramework\Services\IInitialState; use OCP\Collaboration\Reference\RenderReferenceEvent; use OCP\EventDispatcher\IEventDispatcher; use OCP\IConfig; use OCP\IL10N; use OCP\IRequest; class PageController extends Controller { public function __construct( string $appName, IRequest $request, private IL10N $trans, private ProjectService $projectService, private IInitialState $initialStateService, private IAppManager $appManager, private IEventDispatcher $eventDispatcher, private IConfig $config, private ?string $userId ) { parent::__construct($appName, $request); } protected function isDebugModeEnabled(): bool { return $this->config->getSystemValueBool('debug', false); } /** * Main page * * @param string|null $projectId * @param int|null $billId * @return TemplateResponse */ #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)] #[NoAdminRequired] #[NoCSRFRequired] public function index(?string $projectId = null, ?int $billId = null): TemplateResponse { $activityEnabled = $this->appManager->isEnabledForUser('activity'); $this->initialStateService->provideInitialState('activity_enabled', $activityEnabled ? '1' : '0'); $this->initialStateService->provideInitialState('pathProjectId', $projectId ?? ''); $this->initialStateService->provideInitialState('pathBillId', $billId ?? 0); $this->eventDispatcher->dispatchTyped(new RenderReferenceEvent()); $response = new TemplateResponse('cospend', 'main'); $csp = new ContentSecurityPolicy(); $csp->allowEvalScript(); $response->setContentSecurityPolicy($csp); return $response; } /** * @param string $fileName * @param string $color * @return NotFoundResponse|Response */ #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)] #[NoAdminRequired] #[NoCSRFRequired] public function getSvgFromApp(string $fileName, string $color = 'ffffff') { try { $appPath = $this->appManager->getAppPath(Application::APP_ID); } catch (AppPathNotFoundException $e) { return new NotFoundResponse(); } $path = $appPath . "/img/$fileName.svg"; return $this->getSvg($path, $color, $fileName); } private function getSvg(string $path, string $color, string $fileName): Response { if (!Filesystem::isValidPath($path)) { return new NotFoundResponse(); } if (!file_exists($path)) { return new NotFoundResponse(); } $svg = file_get_contents($path); if ($svg === false) { return new NotFoundResponse(); } $svg = $this->colorizeSvg($svg, $color); $response = new DataDisplayResponse($svg, Http::STATUS_OK, ['Content-Type' => 'image/svg+xml']); // Set cache control $ttl = 31536000; $response->cacheFor($ttl); return $response; } private function colorizeSvg(string $svg, string $color): string { if (!preg_match('/^[0-9a-f]{3,6}$/i', $color)) { // Prevent not-sane colors from being written into the SVG $color = '000'; } // add fill (fill is not present on black elements) $fillRe = '/<((circle|rect|path)((?!fill)[a-z0-9 =".\-#():;,])+)\/>/mi'; $svg = preg_replace($fillRe, '<$1 fill="#' . $color . '"/>', $svg); // replace any fill or stroke colors $svg = preg_replace('/stroke="#([a-z0-9]{3,6})"/mi', 'stroke="#' . $color . '"', $svg); $svg = preg_replace('/fill="#([a-z0-9]{3,6})"/mi', 'fill="#' . $color . '"', $svg); return $svg; } /** * Main page * * @param string $projectId * @return TemplateResponse */ #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)] #[NoAdminRequired] #[NoCSRFRequired] public function indexProject(string $projectId): TemplateResponse { return $this->index($projectId); } /** * Main page * * @param string $projectId * @param int $billId * @return TemplateResponse */ #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)] #[NoAdminRequired] #[NoCSRFRequired] public function indexBill(string $projectId, int $billId): TemplateResponse { return $this->index($projectId, $billId); } /** * @param string $token * @return TemplateResponse */ #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)] #[NoAdminRequired] #[NoCSRFRequired] #[PublicPage] #[BruteForceProtection(action: 'CospendPublicShareLinkPage')] public function publicShareLinkPage(string $token): TemplateResponse { $publicShareInfo = $this->projectService->getShareInfoFromShareToken($token); if (!is_null($publicShareInfo)) { $isPasswordProtected = !is_null($publicShareInfo['password'] ?? null); if ($isPasswordProtected) { $params = [ 'token' => $token, 'wrong' => false, ]; $response = new PublicTemplateResponse('cospend', 'sharepassword', $params); $response->setHeaderDetails($this->trans->t('Enter link password of project %s', [$publicShareInfo['projectid']])); $response->setFooterVisible(false); } else { $this->initialStateService->provideInitialState('projectid', $token); $this->initialStateService->provideInitialState('password', 'nopass'); $response = new PublicTemplateResponse('cospend', 'main', []); $csp = new ContentSecurityPolicy(); $csp->allowEvalScript(); $response->setContentSecurityPolicy($csp); $response->setHeaderDetails($this->trans->t('Project %s', [$publicShareInfo['projectid']])); } $response->setHeaderTitle($this->trans->t('Cospend shared link access')); $response->setFooterVisible(false); } else { $templateParams = ['message' => $this->trans->t('No such Cospend share link')]; $response = new TemplateResponse('core', '403', $templateParams, TemplateResponse::RENDER_AS_ERROR); if (!$this->isDebugModeEnabled()) { $throttleMetadata = [ 'reason' => 'wrong token', ]; $response->throttle($throttleMetadata); } } return $response; } /** * @param string $token * @param string|null $password * @return TemplateResponse */ #[OpenAPI(scope: OpenAPI::SCOPE_IGNORE)] #[NoAdminRequired] #[NoCSRFRequired] #[PublicPage] #[BruteForceProtection(action: 'CospendPublicProjectPage')] public function pubProject(string $token, ?string $password = null): TemplateResponse { if ($token && !is_null($password)) { $info = $this->projectService->getShareInfoFromShareToken($token); // if the token is good and no password (or it matches the share one) if (!is_null($info['projectid'] ?? null) && (is_null($info['password'] ?? null) || $password === $info['password']) ) { $this->initialStateService->provideInitialState('projectid', $token); $this->initialStateService->provideInitialState('password', $password); $response = new PublicTemplateResponse('cospend', 'main', []); $response->setHeaderTitle($this->trans->t('Cospend shared link access')); $response->setHeaderDetails($this->trans->t('Project %s', [$info['projectid']])); $response->setFooterVisible(false); $csp = new ContentSecurityPolicy(); $csp->allowEvalScript(); $response->setContentSecurityPolicy($csp); return $response; } elseif (!is_null($info['projectid'] ?? null)) { // good token, incorrect password $params = [ 'token' => $token, 'wrong' => true, ]; $response = new PublicTemplateResponse('cospend', 'sharepassword', $params); $response->setHeaderTitle($this->trans->t('Cospend shared link access')); $response->setHeaderDetails($this->trans->t('Enter link password of project %s', [$info['projectid']])); $response->setFooterVisible(false); if (!$this->isDebugModeEnabled()) { $throttleMetadata = [ 'reason' => 'wrong password', ]; $response->throttle($throttleMetadata); } return $response; } } $templateParams = ['message' => $this->trans->t('No such Cospend share link')]; $response = new TemplateResponse('core', '403', $templateParams, TemplateResponse::RENDER_AS_ERROR); if (!$this->isDebugModeEnabled()) { $throttleMetadata = [ 'reason' => 'wrong token', ]; $response->throttle($throttleMetadata); } return $response; } }