Skip to content

Commit

Permalink
fix(shareManager): Respect empty expireDate in server
Browse files Browse the repository at this point in the history
If `expireDate` is an empty string and not `null` then the server should not set a default.

Signed-off-by: fenn-cs <fenn25.fn@gmail.com>
  • Loading branch information
nfebe committed May 31, 2024
1 parent 67dfc8d commit 63add0a
Show file tree
Hide file tree
Showing 5 changed files with 134 additions and 88 deletions.
9 changes: 5 additions & 4 deletions apps/files_sharing/lib/Controller/ShareAPIController.php
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,8 @@ public function deleteShare(string $id): DataResponse {
* @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.
* 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 @@ public function createShare(
$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
167 changes: 89 additions & 78 deletions lib/private/Share20/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -391,26 +391,6 @@ protected function validateExpirationDateInternal(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);
}
}

// 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 +402,53 @@ protected function validateExpirationDateInternal(IShare $share) {
$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());
$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());
$expirationDate->setTime(0, 0, 0);
$days = (int)$this->config->getAppValue('core', $configProp, (string)$defaultExpireDays);
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());
$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 +481,57 @@ protected function validateExpirationDateInternal(IShare $share) {
*/
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());
$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());
$expirationDate->setTime(0, 0, 0);

$days = (int)$this->config->getAppValue('core', 'link_defaultExpDays', (string)$this->shareApiLinkDefaultExpireDays());
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());
$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
18 changes: 17 additions & 1 deletion lib/private/Share20/Share.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,11 @@ class Share implements IShare {

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

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

private bool $noExpirationDate = false;

public function __construct(IRootFolder $rootFolder, IUserManager $userManager) {
$this->rootFolder = $rootFolder;
$this->userManager = $userManager;
Expand Down Expand Up @@ -421,6 +422,21 @@ public function getExpirationDate() {
return $this->expireDate;
}

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

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

/**
* @inheritdoc
*/
Expand Down
24 changes: 21 additions & 3 deletions lib/public/Share/IShare.php
Original file line number Diff line number Diff line change
Expand Up @@ -385,20 +385,38 @@ public function getNote();
/**
* Set the expiration date
*
* @param null|\DateTime $expireDate
* @param \DateTime|null $expireDate
* @return \OCP\Share\IShare The modified object
* @since 9.0.0
*/
public function setExpirationDate($expireDate);
public function setExpirationDate(\DateTime|null $expireDate);

/**
* Get the expiration date
*
* @return null|\DateTime
* @return \DateTime|null
* @since 9.0.0
*/
public function getExpirationDate();

/**
* Set overwrite flag for falsy expiry date vavlues
*
* @param bool $noExpirationDate
* @return \OCP\Share\IShare The modified object
* @since 28.0.7
*/
public function setNoExpirationDate(bool $noExpirationDate);


/**
* Get value of overwrite falsy expiry date flag
*
* @return bool
* @since 28.0.7
*/
public function getNoExpirationDate();

/**
* Is the share expired ?
*
Expand Down

0 comments on commit 63add0a

Please sign in to comment.