Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[stable28] Respect empty expiryDate value in server #45482

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions apps/files_sharing/lib/Controller/ShareAPIController.php
nfebe marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,8 @@
* @param string $publicUpload If public uploading is allowed
* @param string $password Password for the share
* @param string|null $sendPasswordByTalk Send the password for the share over Talk
* @param string $expireDate Expiry date of the share using user timezone at 00:00. It means date in UTC timezone will be used.
* @param ?string $expireDate The expiry date of the share in the user's timezone (UTC) at 00:00.

Check failure on line 589 in apps/files_sharing/lib/Controller/ShareAPIController.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

MismatchingDocblockParamType

apps/files_sharing/lib/Controller/ShareAPIController.php:589:12: MismatchingDocblockParamType: Parameter $expireDate has wrong type 'null|string', should be 'string' (see https://psalm.dev/141)

Check failure

Code scanning / Psalm

MismatchingDocblockParamType Error

Parameter $expireDate has wrong type 'null|string', should be 'string'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L612 missing?

?string $expireDate = null,

And L793?

		if ($expireDate !== null) {
			if ($expireDate !== '') {

* If $expireDate is not supplied or set to `null`, the system default will be used.
* @param string $note Note for the share
* @param string $label Label for the share (only used in link and email)
* @param string|null $attributes Additional attributes for the share
Expand Down Expand Up @@ -812,19 +813,19 @@
$share->setPermissions($permissions);
} elseif ($shareType === IShare::TYPE_ROOM) {
try {
$this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
$this->getRoomShareHelper()->createShare($share, $shareWith, $permissions, $expireDate ?? '');
} catch (QueryException $e) {
throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$node->getPath()]));
}
} elseif ($shareType === IShare::TYPE_DECK) {
try {
$this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
$this->getDeckShareHelper()->createShare($share, $shareWith, $permissions, $expireDate ?? '');
} catch (QueryException $e) {
throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support room shares', [$node->getPath()]));
}
} elseif ($shareType === IShare::TYPE_SCIENCEMESH) {
try {
$this->getSciencemeshShareHelper()->createShare($share, $shareWith, $permissions, $expireDate);
$this->getSciencemeshShareHelper()->createShare($share, $shareWith, $permissions, $expireDate ?? '');
} catch (QueryException $e) {
throw new OCSForbiddenException($this->l->t('Sharing %s failed because the back end does not support ScienceMesh shares', [$node->getPath()]));
}
Expand Down
4 changes: 2 additions & 2 deletions apps/files_sharing/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1755,10 +1755,10 @@
{
"name": "expireDate",
"in": "query",
"description": "Expiry date of the share using user timezone at 00:00. It means date in UTC timezone will be used.",
"description": "The expiry date of the share in the user's timezone (UTC) at 00:00. If $expireDate is not supplied or set to `null`, the system default will be used.",
"schema": {
"type": "string",
"default": ""
"nullable": true
}
},
{
Expand Down
8 changes: 6 additions & 2 deletions build/integration/features/bootstrap/Sharing.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ public function asCreatingAShareWith($user, $body) {
$fd = $body->getRowsHash();
if (array_key_exists('expireDate', $fd)) {
$dateModification = $fd['expireDate'];
$fd['expireDate'] = date('Y-m-d', strtotime($dateModification));
if (!empty($dateModification)) {
$fd['expireDate'] = date('Y-m-d', strtotime($dateModification));
}
}
$options['form_params'] = $fd;
}
Expand Down Expand Up @@ -328,7 +330,9 @@ public function createShare($user,
public function isFieldInResponse($field, $contentExpected) {
$data = simplexml_load_string($this->response->getBody())->data[0];
if ((string)$field == 'expiration') {
$contentExpected = date('Y-m-d', strtotime($contentExpected)) . " 00:00:00";
if(!empty($contentExpected)) {
$contentExpected = date('Y-m-d', strtotime($contentExpected)) . " 00:00:00";
}
}
if (count($data->element) > 0) {
foreach ($data as $element) {
Expand Down
18 changes: 18 additions & 0 deletions build/integration/sharing_features/sharing-v1.feature
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,24 @@ Feature: sharing
| url | AN_URL |
| mimetype | httpd/unix-directory |

Scenario: Creating a new share with expiration date removed, when default expiration is set
Given user "user0" exists
And user "user1" exists
And parameter "shareapi_default_expire_date" of app "core" is set to "yes"
And As an "user0"
When creating a share with
| path | welcome.txt |
| shareWith | user1 |
| shareType | 0 |
| expireDate | |
Then the OCS status code should be "100"
And the HTTP status code should be "200"
And Getting info of last share
Then the OCS status code should be "100"
And the HTTP status code should be "200"
And Share fields of last share match with
| expiration ||

Scenario: Creating a new public share, updating its password and getting its info
Given user "user0" exists
And As an "user0"
Expand Down
217 changes: 93 additions & 124 deletions lib/private/Share20/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,43 +85,9 @@
* This class is the communication hub for all sharing related operations.
*/
class Manager implements IManager {
/** @var IProviderFactory */
private $factory;
private LoggerInterface $logger;
/** @var IConfig */
private $config;
/** @var ISecureRandom */
private $secureRandom;
/** @var IHasher */
private $hasher;
/** @var IMountManager */
private $mountManager;
/** @var IGroupManager */
private $groupManager;
/** @var IL10N */
private $l;
/** @var IFactory */
private $l10nFactory;
/** @var IUserManager */
private $userManager;
/** @var IRootFolder */
private $rootFolder;
/** @var LegacyHooks */
private $legacyHooks;
/** @var IMailer */
private $mailer;
/** @var IURLGenerator */
private $urlGenerator;
/** @var \OC_Defaults */
private $defaults;
/** @var IEventDispatcher */
private $dispatcher;
/** @var IUserSession */
private $userSession;
/** @var KnownUserService */
private $knownUserService;
private ShareDisableChecker $shareDisableChecker;
private IDateTimeZone $dateTimeZone;

private IL10N|null $l;
private LegacyHooks $legacyHooks;

public function __construct(
LoggerInterface $logger,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
LoggerInterface $logger,
private LoggerInterface $logger,

and further?

Expand All @@ -144,28 +110,20 @@
ShareDisableChecker $shareDisableChecker,
IDateTimeZone $dateTimeZone,
) {
$this->logger = $logger;

Check failure on line 113 in lib/private/Share20/Manager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedThisPropertyAssignment

lib/private/Share20/Manager.php:113:3: UndefinedThisPropertyAssignment: Instance property OC\Share20\Manager::$logger is not defined (see https://psalm.dev/040)
$this->config = $config;

Check failure on line 114 in lib/private/Share20/Manager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedThisPropertyAssignment

lib/private/Share20/Manager.php:114:3: UndefinedThisPropertyAssignment: Instance property OC\Share20\Manager::$config is not defined (see https://psalm.dev/040)
$this->secureRandom = $secureRandom;

Check failure on line 115 in lib/private/Share20/Manager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedThisPropertyAssignment

lib/private/Share20/Manager.php:115:3: UndefinedThisPropertyAssignment: Instance property OC\Share20\Manager::$secureRandom is not defined (see https://psalm.dev/040)
$this->hasher = $hasher;

Check failure on line 116 in lib/private/Share20/Manager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedThisPropertyAssignment

lib/private/Share20/Manager.php:116:3: UndefinedThisPropertyAssignment: Instance property OC\Share20\Manager::$hasher is not defined (see https://psalm.dev/040)
$this->mountManager = $mountManager;

Check failure on line 117 in lib/private/Share20/Manager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedThisPropertyAssignment

lib/private/Share20/Manager.php:117:3: UndefinedThisPropertyAssignment: Instance property OC\Share20\Manager::$mountManager is not defined (see https://psalm.dev/040)
$this->groupManager = $groupManager;

Check failure on line 118 in lib/private/Share20/Manager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedThisPropertyAssignment

lib/private/Share20/Manager.php:118:3: UndefinedThisPropertyAssignment: Instance property OC\Share20\Manager::$groupManager is not defined (see https://psalm.dev/040)
$this->l = $l;
$this->l10nFactory = $l10nFactory;

Check failure on line 120 in lib/private/Share20/Manager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedThisPropertyAssignment

lib/private/Share20/Manager.php:120:3: UndefinedThisPropertyAssignment: Instance property OC\Share20\Manager::$l10nFactory is not defined (see https://psalm.dev/040)
$this->factory = $factory;

Check failure on line 121 in lib/private/Share20/Manager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedThisPropertyAssignment

lib/private/Share20/Manager.php:121:3: UndefinedThisPropertyAssignment: Instance property OC\Share20\Manager::$factory is not defined (see https://psalm.dev/040)
$this->userManager = $userManager;

Check failure on line 122 in lib/private/Share20/Manager.php

View workflow job for this annotation

GitHub Actions / static-code-analysis

UndefinedThisPropertyAssignment

lib/private/Share20/Manager.php:122:3: UndefinedThisPropertyAssignment: Instance property OC\Share20\Manager::$userManager is not defined (see https://psalm.dev/040)
$this->rootFolder = $rootFolder;
// The constructor of LegacyHooks registers the listeners of share events
// do not remove if those are not properly migrated
$this->legacyHooks = new LegacyHooks($dispatcher);
$this->mailer = $mailer;
$this->urlGenerator = $urlGenerator;
$this->defaults = $defaults;
$this->dispatcher = $dispatcher;
$this->userSession = $userSession;
$this->knownUserService = $knownUserService;
$this->shareDisableChecker = $shareDisableChecker;
$this->dateTimeZone = $dateTimeZone;
$this->legacyHooks = new LegacyHooks($this->dispatcher);

Check failure

Code scanning / Psalm

UndefinedThisPropertyFetch Error

Instance property OC\Share20\Manager::$dispatcher is not defined
}

/**
Expand Down Expand Up @@ -391,26 +349,6 @@

$expirationDate = $share->getExpirationDate();

if ($expirationDate !== null) {
$expirationDate->setTimezone($this->dateTimeZone->getTimeZone());
$expirationDate->setTime(0, 0, 0);

$date = new \DateTime('now', $this->dateTimeZone->getTimeZone());
$date->setTime(0, 0, 0);
if ($date >= $expirationDate) {
$message = $this->l->t('Expiration date is in the past');
throw new GenericShareException($message, $message, 404);
}
}

// If expiredate is empty set a default one if there is a default
$fullId = null;
try {
$fullId = $share->getFullId();
} catch (\UnexpectedValueException $e) {
// This is a new share
}

if ($isRemote) {
$defaultExpireDate = $this->shareApiRemoteDefaultExpireDate();
$defaultExpireDays = $this->shareApiRemoteDefaultExpireDays();
Expand All @@ -422,28 +360,53 @@
$configProp = 'internal_defaultExpDays';
$isEnforced = $this->shareApiInternalDefaultExpireDateEnforced();
}
if ($fullId === null && $expirationDate === null && $defaultExpireDate) {
$expirationDate = new \DateTime('now', $this->dateTimeZone->getTimeZone());
$expirationDate->setTime(0, 0, 0);
$days = (int)$this->config->getAppValue('core', $configProp, (string)$defaultExpireDays);
if ($days > $defaultExpireDays) {
$days = $defaultExpireDays;

// If $expirationDate is falsy, noExpirationDate is true and expiration not enforced
// Then skip expiration date validation as null is accepted
if(!($share->getNoExpirationDate() && !$isEnforced)) {
if ($expirationDate != null) {
$expirationDate->setTimezone($this->dateTimeZone->getTimeZone());

Check failure

Code scanning / Psalm

UndefinedThisPropertyFetch Error

Instance property OC\Share20\Manager::$dateTimeZone is not defined
$expirationDate->setTime(0, 0, 0);

$date = new \DateTime('now', $this->dateTimeZone->getTimeZone());
$date->setTime(0, 0, 0);
if ($date >= $expirationDate) {
$message = $this->l->t('Expiration date is in the past');
throw new GenericShareException($message, $message, 404);
}
}
$expirationDate->add(new \DateInterval('P' . $days . 'D'));
}

// If we enforce the expiration date check that is does not exceed
if ($isEnforced) {
if ($expirationDate === null) {
throw new \InvalidArgumentException('Expiration date is enforced');
// If expiredate is empty set a default one if there is a default
$fullId = null;
try {
$fullId = $share->getFullId();
} catch (\UnexpectedValueException $e) {
// This is a new share
}

$date = new \DateTime('now', $this->dateTimeZone->getTimeZone());
$date->setTime(0, 0, 0);
$date->add(new \DateInterval('P' . $defaultExpireDays . 'D'));
if ($date < $expirationDate) {
$message = $this->l->n('Cannot set expiration date more than %n day in the future', 'Cannot set expiration date more than %n days in the future', $defaultExpireDays);
throw new GenericShareException($message, $message, 404);
if ($fullId === null && $expirationDate === null && $defaultExpireDate) {
$expirationDate = new \DateTime('now', $this->dateTimeZone->getTimeZone());

Check failure

Code scanning / Psalm

UndefinedThisPropertyFetch Error

Instance property OC\Share20\Manager::$dateTimeZone is not defined
$expirationDate->setTime(0, 0, 0);
$days = (int)$this->config->getAppValue('core', $configProp, (string)$defaultExpireDays);

Check failure

Code scanning / Psalm

UndefinedThisPropertyFetch Error

Instance property OC\Share20\Manager::$config is not defined
if ($days > $defaultExpireDays) {
$days = $defaultExpireDays;
}
$expirationDate->add(new \DateInterval('P' . $days . 'D'));
}

// If we enforce the expiration date check that is does not exceed
if ($isEnforced) {
if (empty($expirationDate)) {
throw new \InvalidArgumentException('Expiration date is enforced');
}

$date = new \DateTime('now', $this->dateTimeZone->getTimeZone());

Check failure

Code scanning / Psalm

UndefinedThisPropertyFetch Error

Instance property OC\Share20\Manager::$dateTimeZone is not defined
$date->setTime(0, 0, 0);
$date->add(new \DateInterval('P' . $defaultExpireDays . 'D'));
if ($date < $expirationDate) {
$message = $this->l->n('Cannot set expiration date more than %n day in the future', 'Cannot set expiration date more than %n days in the future', $defaultExpireDays);
throw new GenericShareException($message, $message, 404);
}
}
}

Expand Down Expand Up @@ -476,51 +439,57 @@
*/
protected function validateExpirationDateLink(IShare $share) {
$expirationDate = $share->getExpirationDate();

if ($expirationDate !== null) {
$expirationDate->setTimezone($this->dateTimeZone->getTimeZone());
$expirationDate->setTime(0, 0, 0);

$date = new \DateTime('now', $this->dateTimeZone->getTimeZone());
$date->setTime(0, 0, 0);
if ($date >= $expirationDate) {
$message = $this->l->t('Expiration date is in the past');
throw new GenericShareException($message, $message, 404);
$isEnforced = $this->shareApiLinkDefaultExpireDateEnforced();

// If $expirationDate is falsy, noExpirationDate is true and expiration not enforced
// Then skip expiration date validation as null is accepted
if(!($share->getNoExpirationDate() && !$isEnforced)) {
if ($expirationDate !== null) {
$expirationDate->setTimezone($this->dateTimeZone->getTimeZone());

Check failure

Code scanning / Psalm

UndefinedThisPropertyFetch Error

Instance property OC\Share20\Manager::$dateTimeZone is not defined
$expirationDate->setTime(0, 0, 0);

$date = new \DateTime('now', $this->dateTimeZone->getTimeZone());
$date->setTime(0, 0, 0);
if ($date >= $expirationDate) {
$message = $this->l->t('Expiration date is in the past');
throw new GenericShareException($message, $message, 404);
}
}
}

// If expiredate is empty set a default one if there is a default
$fullId = null;
try {
$fullId = $share->getFullId();
} catch (\UnexpectedValueException $e) {
// This is a new share
}

if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
$expirationDate = new \DateTime('now', $this->dateTimeZone->getTimeZone());
$expirationDate->setTime(0, 0, 0);

$days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', (string)$this->shareApiLinkDefaultExpireDays());
if ($days > $this->shareApiLinkDefaultExpireDays()) {
$days = $this->shareApiLinkDefaultExpireDays();
// If expiredate is empty set a default one if there is a default
$fullId = null;
try {
$fullId = $share->getFullId();
} catch (\UnexpectedValueException $e) {
// This is a new share
}

if ($fullId === null && $expirationDate === null && $this->shareApiLinkDefaultExpireDate()) {
$expirationDate = new \DateTime('now', $this->dateTimeZone->getTimeZone());

Check failure

Code scanning / Psalm

UndefinedThisPropertyFetch Error

Instance property OC\Share20\Manager::$dateTimeZone is not defined
$expirationDate->setTime(0, 0, 0);

$days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', (string)$this->shareApiLinkDefaultExpireDays());

Check failure

Code scanning / Psalm

UndefinedThisPropertyFetch Error

Instance property OC\Share20\Manager::$config is not defined
if ($days > $this->shareApiLinkDefaultExpireDays()) {
$days = $this->shareApiLinkDefaultExpireDays();
}
$expirationDate->add(new \DateInterval('P' . $days . 'D'));
}
$expirationDate->add(new \DateInterval('P' . $days . 'D'));
}

// If we enforce the expiration date check that is does not exceed
if ($this->shareApiLinkDefaultExpireDateEnforced()) {
if ($expirationDate === null) {
throw new \InvalidArgumentException('Expiration date is enforced');

// If we enforce the expiration date check that is does not exceed
if ($isEnforced) {
if (empty($expirationDate)) {
throw new \InvalidArgumentException('Expiration date is enforced');
}

$date = new \DateTime('now', $this->dateTimeZone->getTimeZone());

Check failure

Code scanning / Psalm

UndefinedThisPropertyFetch Error

Instance property OC\Share20\Manager::$dateTimeZone is not defined
$date->setTime(0, 0, 0);
$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
if ($date < $expirationDate) {
$message = $this->l->n('Cannot set expiration date more than %n day in the future', 'Cannot set expiration date more than %n days in the future', $this->shareApiLinkDefaultExpireDays());
throw new GenericShareException($message, $message, 404);
}
}

$date = new \DateTime('now', $this->dateTimeZone->getTimeZone());
$date->setTime(0, 0, 0);
$date->add(new \DateInterval('P' . $this->shareApiLinkDefaultExpireDays() . 'D'));
if ($date < $expirationDate) {
$message = $this->l->n('Cannot set expiration date more than %n day in the future', 'Cannot set expiration date more than %n days in the future', $this->shareApiLinkDefaultExpireDays());
throw new GenericShareException($message, $message, 404);
}
}

$accepted = true;
Expand Down
16 changes: 15 additions & 1 deletion lib/private/Share20/Share.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@

/** @var ICacheEntry|null */
private $nodeCacheEntry;

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
private bool $noExpirationDate = false;

Expand Down Expand Up @@ -421,6 +420,21 @@
return $this->expireDate;
}

/**
* @inheritdoc
*/
public function setNoExpirationDate(bool $noExpirationDate) {
$this->noExpirationDate = $noExpirationDate;

Check failure

Code scanning / Psalm

UndefinedThisPropertyAssignment Error

Instance property OC\Share20\Share::$noExpirationDate is not defined
return $this;
}

/**
* @inheritdoc
*/
public function getNoExpirationDate(): bool {
return $this->noExpirationDate;

Check failure

Code scanning / Psalm

UndefinedThisPropertyFetch Error

Instance property OC\Share20\Share::$noExpirationDate is not defined
}

/**
* @inheritdoc
*/
Expand Down
Loading
Loading