2022-11-07 03:36:11 +00:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace OCA\Memories\Controller;
|
|
|
|
|
2023-03-10 02:47:59 +00:00
|
|
|
use OCA\Memories\AppInfo\Application;
|
2023-03-10 17:30:56 +00:00
|
|
|
use OCA\Memories\Db\TimelineQuery;
|
2022-11-07 03:36:11 +00:00
|
|
|
use OCP\App\IAppManager;
|
|
|
|
use OCP\AppFramework\AuthPublicShareController;
|
2022-11-14 02:28:43 +00:00
|
|
|
use OCP\AppFramework\Http\Template\PublicTemplateResponse;
|
2022-11-07 03:36:11 +00:00
|
|
|
use OCP\AppFramework\Http\TemplateResponse;
|
|
|
|
use OCP\AppFramework\Services\IInitialState;
|
|
|
|
use OCP\EventDispatcher\IEventDispatcher;
|
2023-03-10 02:47:59 +00:00
|
|
|
use OCP\Files\IRootFolder;
|
2022-11-07 03:36:11 +00:00
|
|
|
use OCP\Files\NotFoundException;
|
|
|
|
use OCP\IConfig;
|
2023-03-10 17:30:56 +00:00
|
|
|
use OCP\IDBConnection;
|
2022-11-07 03:36:11 +00:00
|
|
|
use OCP\IRequest;
|
|
|
|
use OCP\ISession;
|
|
|
|
use OCP\IURLGenerator;
|
|
|
|
use OCP\IUserManager;
|
2023-03-10 02:47:59 +00:00
|
|
|
use OCP\IUserSession;
|
2022-11-07 03:36:11 +00:00
|
|
|
use OCP\Share\IManager as IShareManager;
|
|
|
|
use OCP\Share\IShare;
|
|
|
|
use OCP\Util;
|
|
|
|
|
|
|
|
class PublicController extends AuthPublicShareController
|
|
|
|
{
|
|
|
|
protected $appName;
|
|
|
|
protected IEventDispatcher $eventDispatcher;
|
|
|
|
protected IInitialState $initialState;
|
2023-03-10 02:47:59 +00:00
|
|
|
protected IUserSession $userSession;
|
|
|
|
protected IRootFolder $rootFolder;
|
2022-11-07 03:36:11 +00:00
|
|
|
protected IShareManager $shareManager;
|
|
|
|
protected IUserManager $userManager;
|
|
|
|
protected IAppManager $appManager;
|
2023-03-10 17:30:56 +00:00
|
|
|
protected IDBConnection $db;
|
2022-11-07 03:36:11 +00:00
|
|
|
protected IConfig $config;
|
|
|
|
|
|
|
|
protected IShare $share;
|
|
|
|
|
|
|
|
public function __construct(
|
|
|
|
string $AppName,
|
|
|
|
IRequest $request,
|
|
|
|
ISession $session,
|
|
|
|
IURLGenerator $urlGenerator,
|
|
|
|
IEventDispatcher $eventDispatcher,
|
|
|
|
IInitialState $initialState,
|
2023-03-10 02:47:59 +00:00
|
|
|
IUserSession $userSession,
|
|
|
|
IRootFolder $rootFolder,
|
2022-11-07 03:36:11 +00:00
|
|
|
IShareManager $shareManager,
|
|
|
|
IUserManager $userManager,
|
|
|
|
IAppManager $appManager,
|
2023-03-10 17:30:56 +00:00
|
|
|
IDBConnection $db,
|
2022-11-07 03:36:11 +00:00
|
|
|
IConfig $config
|
|
|
|
) {
|
|
|
|
parent::__construct($AppName, $request, $session, $urlGenerator);
|
|
|
|
$this->eventDispatcher = $eventDispatcher;
|
|
|
|
$this->initialState = $initialState;
|
2023-03-10 02:47:59 +00:00
|
|
|
$this->userSession = $userSession;
|
|
|
|
$this->rootFolder = $rootFolder;
|
2022-11-07 03:36:11 +00:00
|
|
|
$this->shareManager = $shareManager;
|
|
|
|
$this->userManager = $userManager;
|
|
|
|
$this->appManager = $appManager;
|
2023-03-10 17:30:56 +00:00
|
|
|
$this->db = $db;
|
2022-11-07 03:36:11 +00:00
|
|
|
$this->config = $config;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @PublicPage
|
|
|
|
*
|
|
|
|
* @NoCSRFRequired
|
|
|
|
*
|
|
|
|
* Show the authentication page
|
|
|
|
* The form has to submit to the authenticate method route
|
|
|
|
*/
|
|
|
|
public function showAuthenticate(): TemplateResponse
|
|
|
|
{
|
2023-03-10 02:47:59 +00:00
|
|
|
$this->redirectIfOwned($this->share);
|
|
|
|
|
2022-11-07 03:36:11 +00:00
|
|
|
$templateParameters = ['share' => $this->share];
|
|
|
|
|
|
|
|
return new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest');
|
|
|
|
}
|
|
|
|
|
|
|
|
public function isValidToken(): bool
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
$this->share = $this->shareManager->getShareByToken($this->getToken());
|
|
|
|
|
|
|
|
return true;
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @PublicPage
|
|
|
|
*
|
|
|
|
* @NoCSRFRequired
|
|
|
|
*/
|
|
|
|
public function showShare(): TemplateResponse
|
|
|
|
{
|
|
|
|
// Check whether share exists
|
|
|
|
try {
|
|
|
|
$share = $this->shareManager->getShareByToken($this->getToken());
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
throw new NotFoundException();
|
|
|
|
}
|
|
|
|
|
2022-12-04 17:20:46 +00:00
|
|
|
if (!self::validateShare($share)) {
|
2022-11-07 03:36:11 +00:00
|
|
|
throw new NotFoundException();
|
|
|
|
}
|
|
|
|
|
2023-03-10 02:47:59 +00:00
|
|
|
// Redirect to main app if user owns this share
|
|
|
|
$this->redirectIfOwned($share);
|
|
|
|
|
|
|
|
// Set incognito mode
|
|
|
|
\OC_User::setIncognitoMode(true);
|
|
|
|
|
2022-11-07 03:36:11 +00:00
|
|
|
// Scripts
|
|
|
|
Util::addScript($this->appName, 'memories-main');
|
2023-01-18 03:09:02 +00:00
|
|
|
PageController::provideCommonInitialState($this->initialState);
|
2022-11-09 10:42:42 +00:00
|
|
|
|
2022-12-03 05:25:24 +00:00
|
|
|
// Share info
|
|
|
|
$this->initialState->provideInitialState('no_download', $share->getHideDownload());
|
|
|
|
|
2023-03-10 17:30:56 +00:00
|
|
|
// Share file id only if not a folder
|
|
|
|
$node = $share->getNode();
|
|
|
|
if ($node instanceof \OCP\Files\File) {
|
|
|
|
$this->initialState->provideInitialState('single_item', $this->getSingleItemInitialState($node));
|
|
|
|
}
|
|
|
|
|
2023-03-14 20:20:24 +00:00
|
|
|
// Add OG metadata
|
|
|
|
$params = ['token' => $this->getToken()];
|
|
|
|
$url = $this->urlGenerator->linkToRouteAbsolute('memories.Public.showShare', $params);
|
|
|
|
\OCA\Memories\Util::addOgMetadata($node, $node->getName(), $url, $params);
|
|
|
|
|
|
|
|
// Render the template
|
2022-11-14 02:28:43 +00:00
|
|
|
$response = new PublicTemplateResponse($this->appName, 'main');
|
2023-03-10 17:30:56 +00:00
|
|
|
$response->setHeaderTitle($node->getName());
|
2023-01-04 20:38:44 +00:00
|
|
|
$response->setFooterVisible(false); // wth is that anyway?
|
2023-01-18 03:09:02 +00:00
|
|
|
$response->setContentSecurityPolicy(PageController::getCSP());
|
2023-02-09 08:57:37 +00:00
|
|
|
$response->cacheFor(0);
|
2022-11-07 03:36:11 +00:00
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
2022-12-04 17:20:46 +00:00
|
|
|
/**
|
|
|
|
* Validate the permissions of the share.
|
|
|
|
*/
|
|
|
|
public static function validateShare(?IShare $share): bool
|
|
|
|
{
|
|
|
|
if (null === $share) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get user manager
|
2022-12-04 17:57:31 +00:00
|
|
|
$userManager = \OC::$server->get(IUserManager::class);
|
2022-12-04 17:20:46 +00:00
|
|
|
|
|
|
|
// Check if share read is allowed
|
|
|
|
if (!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the owner is disabled no access to the linke is granted
|
|
|
|
$owner = $userManager->get($share->getShareOwner());
|
|
|
|
if (null === $owner || !$owner->isEnabled()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the initiator of the share is disabled no access is granted
|
|
|
|
$initiator = $userManager->get($share->getSharedBy());
|
|
|
|
if (null === $initiator || !$initiator->isEnabled()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $share->getNode()->isReadable() && $share->getNode()->isShareable();
|
|
|
|
}
|
|
|
|
|
2022-11-07 03:36:11 +00:00
|
|
|
protected function showAuthFailed(): TemplateResponse
|
|
|
|
{
|
|
|
|
$templateParameters = ['share' => $this->share, 'wrongpw' => true];
|
|
|
|
|
|
|
|
return new TemplateResponse('core', 'publicshareauth', $templateParameters, 'guest');
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function verifyPassword(string $password): bool
|
|
|
|
{
|
|
|
|
return $this->shareManager->checkPassword($this->share, $password);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getPasswordHash(): string
|
|
|
|
{
|
|
|
|
return $this->share->getPassword();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function isPasswordProtected(): bool
|
|
|
|
{
|
|
|
|
return null !== $this->share->getPassword();
|
|
|
|
}
|
2023-03-10 02:47:59 +00:00
|
|
|
|
|
|
|
protected function redirectIfOwned(IShare $share)
|
|
|
|
{
|
|
|
|
$user = $this->userSession->getUser();
|
|
|
|
if (!$user) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @var \OCP\Files\Node */
|
|
|
|
$node = null;
|
|
|
|
|
|
|
|
/** @var \OCP\Files\Folder */
|
|
|
|
$userFolder = null;
|
|
|
|
|
|
|
|
// Check if the user has this folder in their root
|
|
|
|
try {
|
|
|
|
$userFolder = $this->rootFolder->getUserFolder($user->getUID());
|
|
|
|
$nodes = $userFolder->getById($share->getNodeId());
|
|
|
|
if (0 === \count($nodes)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
$node = $nodes[0];
|
|
|
|
} catch (NotFoundException $e) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2023-03-10 02:55:22 +00:00
|
|
|
// Check if node is a folder
|
|
|
|
if (!$node instanceof \OCP\Files\Folder) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2023-03-10 02:47:59 +00:00
|
|
|
// Remove user folder path from start of node path
|
|
|
|
$relPath = substr($node->getPath(), \strlen($userFolder->getPath()));
|
|
|
|
|
|
|
|
// Get the user's folders path
|
|
|
|
$foldersPath = $this->config->getUserValue($user->getUID(), Application::APPNAME, 'foldersPath', '/');
|
|
|
|
|
|
|
|
// Check if relPath starts with foldersPath
|
|
|
|
if (0 !== strpos($relPath, $foldersPath)) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove foldersPath from start of relPath
|
|
|
|
$relPath = substr($relPath, \strlen($foldersPath));
|
|
|
|
|
|
|
|
// Redirect to the local path
|
|
|
|
$url = $this->urlGenerator->linkToRouteAbsolute('memories.Page.folder', ['path' => $relPath]);
|
|
|
|
|
|
|
|
// Cannot send a redirect response here because the return
|
|
|
|
// type is a template response for the base class
|
|
|
|
header('HTTP/1.1 302 Found');
|
|
|
|
header('Location: '.$url);
|
|
|
|
|
|
|
|
exit;
|
|
|
|
}
|
2023-03-10 17:30:56 +00:00
|
|
|
|
|
|
|
/** Get initial state of single item */
|
|
|
|
private function getSingleItemInitialState(\OCP\Files\File $file): string
|
|
|
|
{
|
|
|
|
$timelineQuery = new TimelineQuery($this->db);
|
|
|
|
$photo = $timelineQuery->getSingleItem($file->getId());
|
|
|
|
|
|
|
|
return json_encode($photo);
|
|
|
|
}
|
2022-11-07 03:36:11 +00:00
|
|
|
}
|