Skip to content

Commit

Permalink
Merge pull request #46589 from nextcloud/fix/files_sharing-file-reque…
Browse files Browse the repository at this point in the history
…st-followup
  • Loading branch information
skjnldsv authored Jul 19, 2024
2 parents 22efc6d + 725736a commit 0bde47a
Show file tree
Hide file tree
Showing 71 changed files with 790 additions and 217 deletions.
1 change: 1 addition & 0 deletions apps/dav/appinfo/v1/publicwebdav.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@

$view = new \OC\Files\View($node->getPath());
$filesDropPlugin->setView($view);
$filesDropPlugin->setShare($share);

return $view;
});
Expand Down
1 change: 1 addition & 0 deletions apps/dav/appinfo/v2/publicremote.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@

$view = new View($node->getPath());
$filesDropPlugin->setView($view);
$filesDropPlugin->setShare($share);

return $view;
});
Expand Down
52 changes: 39 additions & 13 deletions apps/dav/lib/Files/Sharing/FilesDropPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
namespace OCA\DAV\Files\Sharing;

use OC\Files\View;
use OCP\Share\IShare;
use Sabre\DAV\Exception\MethodNotAllowed;
use Sabre\DAV\ServerPlugin;
use Sabre\HTTP\RequestInterface;
Expand All @@ -16,20 +17,19 @@
*/
class FilesDropPlugin extends ServerPlugin {

/** @var View */
private $view;
private ?View $view = null;
private ?IShare $share = null;
private bool $enabled = false;

/** @var bool */
private $enabled = false;

/**
* @param View $view
*/
public function setView($view) {
public function setView(View $view): void {
$this->view = $view;
}

public function enable() {
public function setShare(IShare $share): void {
$this->share = $share;
}

public function enable(): void {
$this->enabled = true;
}

Expand All @@ -42,25 +42,51 @@ public function enable() {
* @return void
* @throws MethodNotAllowed
*/
public function initialize(\Sabre\DAV\Server $server) {
public function initialize(\Sabre\DAV\Server $server): void {
$server->on('beforeMethod:*', [$this, 'beforeMethod'], 999);
$this->enabled = false;
}

public function beforeMethod(RequestInterface $request, ResponseInterface $response) {
if (!$this->enabled) {
public function beforeMethod(RequestInterface $request, ResponseInterface $response): void {
if (!$this->enabled || $this->share === null || $this->view === null) {
return;
}

// Only allow file drop
if ($request->getMethod() !== 'PUT') {
throw new MethodNotAllowed('Only PUT is allowed on files drop');
}

// Always upload at the root level
$path = explode('/', $request->getPath());
$path = array_pop($path);

// Extract the attributes for the file request
$isFileRequest = false;
$attributes = $this->share->getAttributes();
$nickName = $request->getHeader('X-NC-Nickname');
if ($attributes !== null) {
$isFileRequest = $attributes->getAttribute('fileRequest', 'enabled') === true;
}

// We need a valid nickname for file requests
if ($isFileRequest && ($nickName == null || trim($nickName) === '')) {
throw new MethodNotAllowed('Nickname is required for file requests');
}

// If this is a file request we need to create a folder for the user
if ($isFileRequest) {
// Check if the folder already exists
if (!($this->view->file_exists($nickName) === true)) {
$this->view->mkdir($nickName);
}
// Put all files in the subfolder
$path = $nickName . '/' . $path;
}

$newName = \OC_Helper::buildNotExistingFileNameForView('/', $path, $this->view);
$url = $request->getBaseUrl() . $newName;
$request->setUrl($url);
}

}
15 changes: 15 additions & 0 deletions apps/dav/tests/unit/Files/Sharing/FilesDropPluginTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

use OC\Files\View;
use OCA\DAV\Files\Sharing\FilesDropPlugin;
use OCP\Share\IAttributes;
use OCP\Share\IShare;
use Sabre\DAV\Exception\MethodNotAllowed;
use Sabre\DAV\Server;
use Sabre\HTTP\RequestInterface;
Expand All @@ -18,6 +20,9 @@ class FilesDropPluginTest extends TestCase {
/** @var View|\PHPUnit\Framework\MockObject\MockObject */
private $view;

/** @var IShare|\PHPUnit\Framework\MockObject\MockObject */
private $share;

/** @var Server|\PHPUnit\Framework\MockObject\MockObject */
private $server;

Expand All @@ -34,6 +39,7 @@ protected function setUp(): void {
parent::setUp();

$this->view = $this->createMock(View::class);
$this->share = $this->createMock(IShare::class);
$this->server = $this->createMock(Server::class);
$this->plugin = new FilesDropPlugin();

Expand All @@ -42,6 +48,11 @@ protected function setUp(): void {

$this->response->expects($this->never())
->method($this->anything());

$attributes = $this->createMock(IAttributes::class);
$this->share->expects($this->any())
->method('getAttributes')
->willReturn($attributes);
}

public function testInitialize(): void {
Expand Down Expand Up @@ -69,6 +80,7 @@ public function testNotEnabled(): void {
public function testValid(): void {
$this->plugin->enable();
$this->plugin->setView($this->view);
$this->plugin->setShare($this->share);

$this->request->method('getMethod')
->willReturn('PUT');
Expand All @@ -93,6 +105,7 @@ public function testValid(): void {
public function testFileAlreadyExistsValid(): void {
$this->plugin->enable();
$this->plugin->setView($this->view);
$this->plugin->setShare($this->share);

$this->request->method('getMethod')
->willReturn('PUT');
Expand Down Expand Up @@ -122,6 +135,7 @@ public function testFileAlreadyExistsValid(): void {
public function testNoMKCOL(): void {
$this->plugin->enable();
$this->plugin->setView($this->view);
$this->plugin->setShare($this->share);

$this->request->method('getMethod')
->willReturn('MKCOL');
Expand All @@ -134,6 +148,7 @@ public function testNoMKCOL(): void {
public function testNoSubdirPut(): void {
$this->plugin->enable();
$this->plugin->setView($this->view);
$this->plugin->setShare($this->share);

$this->request->method('getMethod')
->willReturn('PUT');
Expand Down
1 change: 1 addition & 0 deletions apps/files_sharing/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
'OCA\\Files_Sharing\\Listener\\BeforeDirectFileDownloadListener' => $baseDir . '/../lib/Listener/BeforeDirectFileDownloadListener.php',
'OCA\\Files_Sharing\\Listener\\BeforeZipCreatedListener' => $baseDir . '/../lib/Listener/BeforeZipCreatedListener.php',
'OCA\\Files_Sharing\\Listener\\LoadAdditionalListener' => $baseDir . '/../lib/Listener/LoadAdditionalListener.php',
'OCA\\Files_Sharing\\Listener\\LoadPublicFileRequestAuthListener' => $baseDir . '/../lib/Listener/LoadPublicFileRequestAuthListener.php',
'OCA\\Files_Sharing\\Listener\\LoadSidebarListener' => $baseDir . '/../lib/Listener/LoadSidebarListener.php',
'OCA\\Files_Sharing\\Listener\\ShareInteractionListener' => $baseDir . '/../lib/Listener/ShareInteractionListener.php',
'OCA\\Files_Sharing\\Listener\\UserAddedToGroupListener' => $baseDir . '/../lib/Listener/UserAddedToGroupListener.php',
Expand Down
1 change: 1 addition & 0 deletions apps/files_sharing/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ class ComposerStaticInitFiles_Sharing
'OCA\\Files_Sharing\\Listener\\BeforeDirectFileDownloadListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeDirectFileDownloadListener.php',
'OCA\\Files_Sharing\\Listener\\BeforeZipCreatedListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeZipCreatedListener.php',
'OCA\\Files_Sharing\\Listener\\LoadAdditionalListener' => __DIR__ . '/..' . '/../lib/Listener/LoadAdditionalListener.php',
'OCA\\Files_Sharing\\Listener\\LoadPublicFileRequestAuthListener' => __DIR__ . '/..' . '/../lib/Listener/LoadPublicFileRequestAuthListener.php',
'OCA\\Files_Sharing\\Listener\\LoadSidebarListener' => __DIR__ . '/..' . '/../lib/Listener/LoadSidebarListener.php',
'OCA\\Files_Sharing\\Listener\\ShareInteractionListener' => __DIR__ . '/..' . '/../lib/Listener/ShareInteractionListener.php',
'OCA\\Files_Sharing\\Listener\\UserAddedToGroupListener' => __DIR__ . '/..' . '/../lib/Listener/UserAddedToGroupListener.php',
Expand Down
6 changes: 5 additions & 1 deletion apps/files_sharing/js/files_drop.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
// note: password not be required, the endpoint
// will recognize previous validation from the session
root: OC.getRootPath() + '/public.php/dav/files/' + $('#sharingToken').val() + '/',
useHTTPS: OC.getProtocol() === 'https'
useHTTPS: OC.getProtocol() === 'https',
});

// We only process one file at a time 🤷‍♀️
Expand All @@ -47,6 +47,10 @@
data.headers = {};
}

if (localStorage.getItem('nick') !== null) {
data.headers['X-NC-Nickname'] = localStorage.getItem('nick')
}

$('#drop-upload-done-indicator').addClass('hidden');
$('#drop-upload-progress-indicator').removeClass('hidden');

Expand Down
7 changes: 6 additions & 1 deletion apps/files_sharing/lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
use OCA\Files_Sharing\Listener\BeforeDirectFileDownloadListener;
use OCA\Files_Sharing\Listener\BeforeZipCreatedListener;
use OCA\Files_Sharing\Listener\LoadAdditionalListener;
use OCA\Files_Sharing\Listener\LoadPublicFileRequestAuthListener;
use OCA\Files_Sharing\Listener\LoadSidebarListener;
use OCA\Files_Sharing\Listener\ShareInteractionListener;
use OCA\Files_Sharing\Listener\UserAddedToGroupListener;
Expand All @@ -34,6 +35,7 @@
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
use OCP\Collaboration\Resources\LoadAdditionalScriptsEvent as ResourcesLoadAdditionalScriptsEvent;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Federation\ICloudIdManager;
Expand Down Expand Up @@ -85,7 +87,7 @@ function () use ($c) {
$context->registerEventListener(GroupChangedEvent::class, GroupDisplayNameCache::class);
$context->registerEventListener(GroupDeletedEvent::class, GroupDisplayNameCache::class);

// sidebar and files scripts
// Sidebar and files scripts
$context->registerEventListener(LoadAdditionalScriptsEvent::class, LoadAdditionalListener::class);
$context->registerEventListener(LoadSidebar::class, LoadSidebarListener::class);
$context->registerEventListener(ShareCreatedEvent::class, ShareInteractionListener::class);
Expand All @@ -95,6 +97,9 @@ function () use ($c) {
// Handle download events for view only checks
$context->registerEventListener(BeforeZipCreatedEvent::class, BeforeZipCreatedListener::class);
$context->registerEventListener(BeforeDirectFileDownloadEvent::class, BeforeDirectFileDownloadListener::class);

// File request auth
$context->registerEventListener(BeforeTemplateRenderedEvent::class, LoadPublicFileRequestAuthListener::class);
}

public function boot(IBootContext $context): void {
Expand Down
6 changes: 4 additions & 2 deletions apps/files_sharing/lib/Controller/ShareAPIController.php
Original file line number Diff line number Diff line change
Expand Up @@ -596,8 +596,10 @@ public function createShare(
throw new OCSNotFoundException($this->l->t('Invalid permissions'));
}

// Shares always require read permissions
$permissions |= Constants::PERMISSION_READ;
// Shares always require read permissions OR create permissions
if (($permissions & Constants::PERMISSION_READ) === 0 && ($permissions & Constants::PERMISSION_CREATE) === 0) {
$permissions |= Constants::PERMISSION_READ;
}

if ($node instanceof \OCP\Files\File) {
// Single file shares should never have delete or create permissions
Expand Down
55 changes: 25 additions & 30 deletions apps/files_sharing/lib/DefaultPublicShareTemplateProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
use OCP\AppFramework\Http\Template\PublicTemplateResponse;
use OCP\AppFramework\Http\Template\SimpleMenuAction;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
use OCP\Constants;
use OCP\Defaults;
use OCP\EventDispatcher\IEventDispatcher;
Expand All @@ -37,39 +38,20 @@
use OCP\Util;

class DefaultPublicShareTemplateProvider implements IPublicShareTemplateProvider {
private IUserManager $userManager;
private IAccountManager $accountManager;
private IPreview $previewManager;
protected FederatedShareProvider $federatedShareProvider;
private IURLGenerator $urlGenerator;
private IEventDispatcher $eventDispatcher;
private IL10N $l10n;
private Defaults $defaults;
private IConfig $config;
private IRequest $request;

public function __construct(
IUserManager $userManager,
IAccountManager $accountManager,
IPreview $previewManager,
FederatedShareProvider $federatedShareProvider,
IUrlGenerator $urlGenerator,
IEventDispatcher $eventDispatcher,
IL10N $l10n,
Defaults $defaults,
IConfig $config,
IRequest $request
private IUserManager $userManager,
private IAccountManager $accountManager,
private IPreview $previewManager,
protected FederatedShareProvider $federatedShareProvider,
private IUrlGenerator $urlGenerator,
private IEventDispatcher $eventDispatcher,
private IL10N $l10n,
private Defaults $defaults,
private IConfig $config,
private IRequest $request,
private IInitialState $initialState,
) {
$this->userManager = $userManager;
$this->accountManager = $accountManager;
$this->previewManager = $previewManager;
$this->federatedShareProvider = $federatedShareProvider;
$this->urlGenerator = $urlGenerator;
$this->eventDispatcher = $eventDispatcher;
$this->l10n = $l10n;
$this->defaults = $defaults;
$this->config = $config;
$this->request = $request;
}

public function shouldRespond(IShare $share): bool {
Expand All @@ -91,11 +73,19 @@ public function renderPage(IShare $share, string $token, string $path): Template
if ($ownerName->getScope() === IAccountManager::SCOPE_PUBLISHED) {
$shareTmpl['owner'] = $owner->getUID();
$shareTmpl['shareOwner'] = $owner->getDisplayName();
$this->initialState->provideInitialState('owner', $shareTmpl['owner']);
$this->initialState->provideInitialState('ownerDisplayName', $shareTmpl['shareOwner']);
}
}

// Provide initial state
$this->initialState->provideInitialState('label', $share->getLabel());
$this->initialState->provideInitialState('note', $share->getNote());
$this->initialState->provideInitialState('filename', $shareNode->getName());

$shareTmpl['filename'] = $shareNode->getName();
$shareTmpl['directory_path'] = $share->getTarget();
$shareTmpl['label'] = $share->getLabel();
$shareTmpl['note'] = $share->getNote();
$shareTmpl['mimetype'] = $shareNode->getMimetype();
$shareTmpl['previewSupported'] = $this->previewManager->isMimeSupported($shareNode->getMimetype());
Expand Down Expand Up @@ -240,6 +230,11 @@ public function renderPage(IShare $share, string $token, string $path): Template
$response->setHeaderDetails($this->l10n->t('shared by %s', [$shareTmpl['shareOwner']]));
}

// If the share has a label, use it as the title
if ($shareTmpl['label'] !== '') {
$response->setHeaderTitle($shareTmpl['label']);
}

$isNoneFileDropFolder = $shareIsFolder === false || $share->getPermissions() !== Constants::PERMISSION_CREATE;

if ($isNoneFileDropFolder && !$share->getHideDownload()) {
Expand Down
Loading

0 comments on commit 0bde47a

Please sign in to comment.