diff --git a/cypress/e2e/direct.spec.js b/cypress/e2e/direct.spec.js index 2ddcd5a3a4..8254ccd01d 100644 --- a/cypress/e2e/direct.spec.js +++ b/cypress/e2e/direct.spec.js @@ -85,6 +85,7 @@ describe('Direct editing (legacy)', function() { cy.nextcloudTestingAppConfigSet('richdocuments', 'uiDefaults-UIMode', 'classic') cy.logout() cy.visit(token) + cy.screenshot('direct') cy.waitForCollabora(false) cy.screenshot('direct') }) diff --git a/cypress/e2e/open.spec.js b/cypress/e2e/open.spec.js index 8c27845451..b9bd591cd1 100644 --- a/cypress/e2e/open.spec.js +++ b/cypress/e2e/open.spec.js @@ -55,8 +55,8 @@ describe('Open existing office files', function() { // Share action cy.get('@loleafletframe').within(() => { - cy.get('#main-menu #menu-file > a').click() - cy.get('#main-menu #menu-shareas > a').click() + cy.get('#main-menu li#menu-file > a').click() + cy.get('#main-menu li#menu-shareas > a').click() }) cy.get('#app-sidebar-vue') diff --git a/cypress/e2e/settings.spec.js b/cypress/e2e/settings.spec.js index 3df9538b88..6315a40e5d 100644 --- a/cypress/e2e/settings.spec.js +++ b/cypress/e2e/settings.spec.js @@ -20,7 +20,7 @@ import { User } from '@nextcloud/cypress' const usesHttps = Cypress.env('baseUrl').substr(0, 5) === 'https' -const collaboraUrl = Cypress.env('collaboraUrl') +const collaboraUrl = Cypress.config('collaboraUrl') const defaultFonts = ['AmaticSC-Regular.ttf'] describe('Office admin settings', function() { diff --git a/cypress/e2e/share-link.js b/cypress/e2e/share-link.js index c6a6255d65..8fc7697846 100644 --- a/cypress/e2e/share-link.js +++ b/cypress/e2e/share-link.js @@ -51,7 +51,7 @@ describe('Public sharing of office documents', function() { cy.spy(win, 'postMessage').as('postMessage') }, }) - cy.waitForCollabora(true) + cy.waitForCollabora() cy.get('@loleafletframe').within(() => { cy.get('#closebutton').click() }) diff --git a/lib/AppConfig.php b/lib/AppConfig.php index b2db4068ef..d70e735a09 100644 --- a/lib/AppConfig.php +++ b/lib/AppConfig.php @@ -61,7 +61,7 @@ public function __construct( ) { } - public function getAppNamespace($key) { + public function getAppNamespace(string $key) { if (str_starts_with($key, 'watermark_')) { return self::WATERMARK_APP_NAMESPACE; } @@ -85,7 +85,7 @@ public function getAppValue($key, $defaultValue = null) { * @param $key * @return list|string */ - public function getAppValueArray($key) { + public function getAppValueArray(string $key) { $value = $this->config->getAppValue($this->getAppNamespace($key), $key, []); if (array_key_exists($key, self::APP_SETTING_TYPES) && self::APP_SETTING_TYPES[$key] === 'array') { $value = $value !== '' ? explode(',', $value) : []; diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php index 084edf8bf2..59a4141b65 100644 --- a/lib/AppInfo/Application.php +++ b/lib/AppInfo/Application.php @@ -33,6 +33,7 @@ use OCA\Richdocuments\Listener\BeforeFetchPreviewListener; use OCA\Richdocuments\Listener\BeforeTemplateRenderedListener; use OCA\Richdocuments\Listener\FileCreatedFromTemplateListener; +use OCA\Richdocuments\Listener\LoadPublicViewerListener; use OCA\Richdocuments\Listener\LoadViewerListener; use OCA\Richdocuments\Listener\ReferenceListener; use OCA\Richdocuments\Listener\ShareLinkListener; @@ -81,6 +82,7 @@ public function register(IRegistrationContext $context): void { $context->registerEventListener(FileCreatedFromTemplateEvent::class, FileCreatedFromTemplateListener::class); $context->registerEventListener(AddContentSecurityPolicyEvent::class, AddContentSecurityPolicyListener::class); $context->registerEventListener(AddFeaturePolicyEvent::class, AddFeaturePolicyListener::class); + $context->registerEventListener(BeforeTemplateRenderedEvent::class, LoadPublicViewerListener::class); $context->registerEventListener(LoadViewer::class, LoadViewerListener::class); $context->registerEventListener(ShareLinkAccessedEvent::class, ShareLinkListener::class); $context->registerEventListener(BeforePreviewFetchedEvent::class, BeforeFetchPreviewListener::class); diff --git a/lib/Controller/DirectViewController.php b/lib/Controller/DirectViewController.php index 02097675ad..f08ea2d0dc 100644 --- a/lib/Controller/DirectViewController.php +++ b/lib/Controller/DirectViewController.php @@ -189,7 +189,10 @@ public function showPublicShare(Direct $direct) { return new TemplateResponse('core', '403', [], 'guest'); } - private function renderErrorPage($message) { + /** + * @psalm-param 'Failed to open the requested file.' $message + */ + private function renderErrorPage(string $message) { $params = [ 'errors' => [['error' => $message]] ]; diff --git a/lib/Controller/OCSController.php b/lib/Controller/OCSController.php index 50504f1527..8a1b60ae19 100644 --- a/lib/Controller/OCSController.php +++ b/lib/Controller/OCSController.php @@ -345,7 +345,7 @@ public function createFromTemplate($path, $template) { } } - private function mb_pathinfo($filepath) { + private function mb_pathinfo(string $filepath) { $result = []; preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', ltrim('/' . $filepath), $matches); if ($matches[1]) { diff --git a/lib/Controller/TemplatesController.php b/lib/Controller/TemplatesController.php index fa63567840..70aa4c0961 100644 --- a/lib/Controller/TemplatesController.php +++ b/lib/Controller/TemplatesController.php @@ -82,7 +82,9 @@ public function __construct($appName, /** * @NoAdminRequired + * * @NoCSRFRequired + * * @PublicPage * * Get preview for a specific template @@ -93,15 +95,17 @@ public function __construct($appName, * @param bool $a * @param bool $forceIcon * @param string $mode - * @return DataResponse + * * @throws NotFoundResponse + * + * @psalm-return DataResponse<400|404, array, array>|DataResponse>|FileDisplayResponse> */ public function getPreview($fileId, $x = 150, $y = 150, $a = false, $forceIcon = true, - $mode = 'fill') { + $mode = 'fill'): DataResponse|FileDisplayResponse { if ($fileId === '' || $x === 0 || $y === 0) { return new DataResponse([], Http::STATUS_BAD_REQUEST); } diff --git a/lib/Db/AssetMapper.php b/lib/Db/AssetMapper.php index 67c0b0824d..bc261d2fe3 100644 --- a/lib/Db/AssetMapper.php +++ b/lib/Db/AssetMapper.php @@ -45,11 +45,12 @@ public function __construct(IDBConnection $db, ISecureRandom $random, ITimeFacto } /** - * @param $uid + * @param null|string $uid * @param $fileid + * * @return Asset */ - public function newAsset($uid, $fileid) { + public function newAsset(string|null $uid, int $fileid) { $asset = new Asset(); $asset->setUid($uid); $asset->setFileid($fileid); diff --git a/lib/Db/DirectMapper.php b/lib/Db/DirectMapper.php index 31f451c193..575ac2dc69 100644 --- a/lib/Db/DirectMapper.php +++ b/lib/Db/DirectMapper.php @@ -50,9 +50,13 @@ public function __construct(IDBConnection $db, * @param string|null $uid * @param int $fileid * @param int $destination + * @param null|string $share + * @param null|string $initiatorHost + * @param null|string $initiatorToken + * * @return Direct */ - public function newDirect($uid, $fileid, $destination = null, $share = null, $initiatorHost = null, $initiatorToken = null) { + public function newDirect($uid, $fileid, $destination = null, string|null $share = null, string|null $initiatorHost = null, string|null $initiatorToken = null) { $direct = new Direct(); $direct->setUid($uid); $direct->setFileid($fileid); diff --git a/lib/Db/WopiMapper.php b/lib/Db/WopiMapper.php index 65e58b3768..2f27921087 100644 --- a/lib/Db/WopiMapper.php +++ b/lib/Db/WopiMapper.php @@ -98,7 +98,7 @@ public function generateFileToken($fileId, $owner, $editor, $version, $updatable return $wopi; } - public function generateInitiatorToken($uid, $remoteServer) { + public function generateInitiatorToken(string $uid, string $remoteServer) { $token = $this->random->generate(32, ISecureRandom::CHAR_LOWER . ISecureRandom::CHAR_UPPER . ISecureRandom::CHAR_DIGITS); $wopi = Wopi::fromParams([ diff --git a/lib/Listener/LoadPublicViewerListener.php b/lib/Listener/LoadPublicViewerListener.php new file mode 100644 index 0000000000..bba1bb4ccb --- /dev/null +++ b/lib/Listener/LoadPublicViewerListener.php @@ -0,0 +1,50 @@ + + * + * @author Elizabeth Danzberger + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + + +namespace OCA\Richdocuments\Listener; + +use OCA\Richdocuments\AppInfo\Application; +use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; +use OCP\AppFramework\Http\TemplateResponse; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\Util; + +class LoadPublicViewerListener implements IEventListener { + public function handle(Event $event): void { + if (!$event instanceof BeforeTemplateRenderedEvent) { + return; + } + + if ($event->getResponse()->getRenderAs() !== TemplateResponse::RENDER_AS_PUBLIC) { + return; + } + + Util::addScript(Application::APPNAME, 'richdocuments-public'); + } +} diff --git a/lib/Preview/Office.php b/lib/Preview/Office.php index daaa30328d..351e2b008d 100644 --- a/lib/Preview/Office.php +++ b/lib/Preview/Office.php @@ -25,7 +25,6 @@ use OCA\Richdocuments\Capabilities; use OCP\Files\File; use OCP\Http\Client\IClientService; -use OCP\IImage; use OCP\Image; use OCP\Preview\IProviderV2; use Psr\Log\LoggerInterface; @@ -47,7 +46,7 @@ public function isAvailable(\OCP\Files\FileInfo $file): bool { /** * {@inheritDoc} */ - public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage { + public function getThumbnail(File $file, int $maxX, int $maxY): Image|null { if ($file->getSize() === 0) { return null; } diff --git a/lib/Service/CapabilitiesService.php b/lib/Service/CapabilitiesService.php index 6edf8aa6c9..e6bfb25618 100644 --- a/lib/Service/CapabilitiesService.php +++ b/lib/Service/CapabilitiesService.php @@ -148,7 +148,7 @@ public function getCapabilitiesEndpoint(): ?string { return rtrim($remoteHost, '/') . '/hosting/capabilities'; } - public function fetchFromRemote($throw = false): void { + public function fetchFromRemote(bool $throw = false): void { if (!$this->getCapabilitiesEndpoint()) { return; } diff --git a/lib/Service/DemoService.php b/lib/Service/DemoService.php index 01f9512cba..721189b6b2 100644 --- a/lib/Service/DemoService.php +++ b/lib/Service/DemoService.php @@ -41,7 +41,7 @@ public function __construct(ICache $cache, IClientService $clientService) { $this->clientService = $clientService; } - public function fetchDemoServers($refresh = false) { + public function fetchDemoServers(bool $refresh = false) { $servers = $this->cache->get('richdocuments-demo'); if (!$refresh) { return json_decode($servers, true); diff --git a/lib/Service/FederationService.php b/lib/Service/FederationService.php index ca3caae5cc..0e95b5e91d 100644 --- a/lib/Service/FederationService.php +++ b/lib/Service/FederationService.php @@ -95,7 +95,7 @@ public function getTrustedServers(): array { * @return string * @throws \Exception */ - public function getRemoteCollaboraURL($remote) { + public function getRemoteCollaboraURL(string $remote) { // If no protocol is provided we default to https if (strpos($remote, 'http://') !== 0 && strpos($remote, 'https://') !== 0) { $remote = 'https://' . $remote; @@ -122,7 +122,7 @@ public function getRemoteCollaboraURL($remote) { return ''; } - public function isTrustedRemote($domainWithPort) { + public function isTrustedRemote(string $domainWithPort) { if (strpos($domainWithPort, 'http://') === 0 || strpos($domainWithPort, 'https://') === 0) { $port = parse_url($domainWithPort, PHP_URL_PORT); $domainWithPort = parse_url($domainWithPort, PHP_URL_HOST) . ($port ? ':' . $port : ''); diff --git a/lib/Service/FileTargetService.php b/lib/Service/FileTargetService.php index 14a9b4fb3b..789fb66c6a 100644 --- a/lib/Service/FileTargetService.php +++ b/lib/Service/FileTargetService.php @@ -78,7 +78,7 @@ public function getFileTargets(File $file): array { return $categories; } - public function getTargetPreview($file, $target) { + public function getTargetPreview(File $file, string $target) { return $this->remoteService->fetchTargetThumbnail($file, $target); } diff --git a/lib/Service/FontService.php b/lib/Service/FontService.php index 99b8ea7d3a..3d818ba63a 100644 --- a/lib/Service/FontService.php +++ b/lib/Service/FontService.php @@ -149,8 +149,10 @@ static function (ISimpleFile $f) use ($url) { /** * @param string $fileName - * @param $newFileResource + * @param resource $newFileResource + * * @return array + * * @throws \OCP\Files\NotPermittedException */ public function uploadFontFile(string $fileName, $newFileResource): array { diff --git a/lib/Service/RemoteService.php b/lib/Service/RemoteService.php index fff74edb6f..4385a24964 100644 --- a/lib/Service/RemoteService.php +++ b/lib/Service/RemoteService.php @@ -20,7 +20,7 @@ public function __construct( ) { } - public function fetchTargets($file): array { + public function fetchTargets(File $file): array { $client = $this->clientService->newClient(); try { $response = $client->put( diff --git a/lib/Template/CollaboraTemplateProvider.php b/lib/Template/CollaboraTemplateProvider.php index 07e9906007..3c0666cc87 100644 --- a/lib/Template/CollaboraTemplateProvider.php +++ b/lib/Template/CollaboraTemplateProvider.php @@ -52,6 +52,11 @@ public function getTemplateType(): string { return CollaboraTemplateProvider::class; } + /** + * @return Template[] + * + * @psalm-return array