Skip to content

Commit 045f8cc

Browse files
author
Vincent Petry
committed
Merge pull request #18651 from owncloud/ocs_share_create_with_expire
Allow to directly set the expireDate on a new (link)share
2 parents 114d1ac + 2aff11c commit 045f8cc

File tree

3 files changed

+198
-3
lines changed

3 files changed

+198
-3
lines changed

apps/files_sharing/api/local.php

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,7 @@ public static function createShare($params) {
258258
$itemSource = self::getFileId($path);
259259
$itemSourceName = $itemSource;
260260
$itemType = self::getItemType($path);
261+
$expirationDate = null;
261262

262263
if($itemSource === null) {
263264
return new \OC_OCS_Result(null, 404, "wrong path, file/folder doesn't exist.");
@@ -286,6 +287,14 @@ public static function createShare($params) {
286287
// read, create, update (7) if public upload is enabled or
287288
// read (1) if public upload is disabled
288289
$permissions = $publicUpload === 'true' ? 7 : 1;
290+
291+
// Get the expiration date
292+
try {
293+
$expirationDate = isset($_POST['expireDate']) ? self::parseDate($_POST['expireDate']) : null;
294+
} catch (\Exception $e) {
295+
return new \OC_OCS_Result(null, 404, 'Invalid Date. Format must be YYYY-MM-DD.');
296+
}
297+
289298
break;
290299
default:
291300
return new \OC_OCS_Result(null, 400, "unknown share type");
@@ -302,10 +311,15 @@ public static function createShare($params) {
302311
$shareType,
303312
$shareWith,
304313
$permissions,
305-
$itemSourceName
306-
);
314+
$itemSourceName,
315+
$expirationDate
316+
);
307317
} catch (HintException $e) {
308-
return new \OC_OCS_Result(null, 400, $e->getHint());
318+
if ($e->getCode() === 0) {
319+
return new \OC_OCS_Result(null, 400, $e->getHint());
320+
} else {
321+
return new \OC_OCS_Result(null, $e->getCode(), $e->getHint());
322+
}
309323
} catch (\Exception $e) {
310324
return new \OC_OCS_Result(null, 403, $e->getMessage());
311325
}
@@ -537,6 +551,30 @@ public static function deleteShare($params) {
537551
}
538552
}
539553

554+
/**
555+
* Make sure that the passed date is valid ISO 8601
556+
* So YYYY-MM-DD
557+
* If not throw an exception
558+
*
559+
* @param string $expireDate
560+
*
561+
* @throws \Exception
562+
* @return \DateTime
563+
*/
564+
private static function parseDate($expireDate) {
565+
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $expireDate) === 0) {
566+
throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
567+
}
568+
569+
$date = new \DateTime($expireDate);
570+
571+
if ($date === false) {
572+
throw new \Exception('Invalid date. Format must be YYYY-MM-DD');
573+
}
574+
575+
return $date;
576+
}
577+
540578
/**
541579
* get file ID from a given path
542580
* @param string $path

apps/files_sharing/tests/api.php

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,4 +1487,146 @@ public function testDefaultExpireDate() {
14871487
$config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
14881488

14891489
}
1490+
1491+
public function datesProvider() {
1492+
$date = new \DateTime();
1493+
$date->add(new \DateInterval('P5D'));
1494+
1495+
$year = (int)$date->format('Y');
1496+
1497+
return [
1498+
[$date->format('Y-m-d'), true],
1499+
[$year+1 . '-1-1', false],
1500+
[$date->format('Y-m-dTH:m'), false],
1501+
['abc', false],
1502+
[$date->format('Y-m-d') . 'xyz', false],
1503+
];
1504+
}
1505+
1506+
/**
1507+
* Make sure only ISO 8601 dates are accepted
1508+
*
1509+
* @dataProvider datesProvider
1510+
*/
1511+
public function testPublicLinkExpireDate($date, $valid) {
1512+
$_POST['path'] = $this->folder;
1513+
$_POST['shareType'] = \OCP\Share::SHARE_TYPE_LINK;
1514+
$_POST['expireDate'] = $date;
1515+
1516+
$result = \OCA\Files_Sharing\API\Local::createShare([]);
1517+
1518+
if ($valid === false) {
1519+
$this->assertFalse($result->succeeded());
1520+
$this->assertEquals(404, $result->getStatusCode());
1521+
$this->assertEquals('Invalid Date. Format must be YYYY-MM-DD.', $result->getMeta()['message']);
1522+
return;
1523+
}
1524+
1525+
$this->assertTrue($result->succeeded());
1526+
1527+
$data = $result->getData();
1528+
$this->assertTrue(is_string($data['token']));
1529+
1530+
// check for correct link
1531+
$url = \OC::$server->getURLGenerator()->getAbsoluteURL('/index.php/s/' . $data['token']);
1532+
$this->assertEquals($url, $data['url']);
1533+
1534+
1535+
$share = $this->getShareFromId($data['id']);
1536+
$items = \OCP\Share::getItemShared('file', $share['item_source']);
1537+
$this->assertTrue(!empty($items));
1538+
1539+
$item = reset($items);
1540+
$this->assertTrue(is_array($item));
1541+
$this->assertEquals($date, substr($item['expiration'], 0, 10));
1542+
1543+
$fileinfo = $this->view->getFileInfo($this->folder);
1544+
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
1545+
}
1546+
1547+
public function testCreatePublicLinkExpireDateValid() {
1548+
$config = \OC::$server->getConfig();
1549+
1550+
// enforce expire date, by default 7 days after the file was shared
1551+
$config->setAppValue('core', 'shareapi_default_expire_date', 'yes');
1552+
$config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes');
1553+
1554+
$date = new \DateTime();
1555+
$date->add(new \DateInterval('P5D'));
1556+
1557+
$_POST['path'] = $this->folder;
1558+
$_POST['shareType'] = \OCP\Share::SHARE_TYPE_LINK;
1559+
$_POST['expireDate'] = $date->format('Y-m-d');
1560+
1561+
$result = \OCA\Files_Sharing\API\Local::createShare([]);
1562+
1563+
$this->assertTrue($result->succeeded());
1564+
1565+
$data = $result->getData();
1566+
$this->assertTrue(is_string($data['token']));
1567+
1568+
// check for correct link
1569+
$url = \OC::$server->getURLGenerator()->getAbsoluteURL('/index.php/s/' . $data['token']);
1570+
$this->assertEquals($url, $data['url']);
1571+
1572+
1573+
$share = $this->getShareFromId($data['id']);
1574+
$items = \OCP\Share::getItemShared('file', $share['item_source']);
1575+
$this->assertTrue(!empty($items));
1576+
1577+
$item = reset($items);
1578+
$this->assertTrue(is_array($item));
1579+
$this->assertEquals($date->format('Y-m-d'), substr($item['expiration'], 0, 10));
1580+
1581+
$fileinfo = $this->view->getFileInfo($this->folder);
1582+
\OCP\Share::unshare('folder', $fileinfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, null);
1583+
1584+
$config->setAppValue('core', 'shareapi_default_expire_date', 'no');
1585+
$config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
1586+
}
1587+
1588+
public function testCreatePublicLinkExpireDateInvalidFuture() {
1589+
$config = \OC::$server->getConfig();
1590+
1591+
// enforce expire date, by default 7 days after the file was shared
1592+
$config->setAppValue('core', 'shareapi_default_expire_date', 'yes');
1593+
$config->setAppValue('core', 'shareapi_enforce_expire_date', 'yes');
1594+
1595+
$date = new \DateTime();
1596+
$date->add(new \DateInterval('P8D'));
1597+
1598+
$_POST['path'] = $this->folder;
1599+
$_POST['shareType'] = \OCP\Share::SHARE_TYPE_LINK;
1600+
$_POST['expireDate'] = $date->format('Y-m-d');
1601+
1602+
$result = \OCA\Files_Sharing\API\Local::createShare([]);
1603+
1604+
$this->assertFalse($result->succeeded());
1605+
$this->assertEquals(404, $result->getStatusCode());
1606+
$this->assertEquals('Cannot set expiration date. Shares cannot expire later than 7 after they have been shared', $result->getMeta()['message']);
1607+
1608+
$config->setAppValue('core', 'shareapi_default_expire_date', 'no');
1609+
$config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
1610+
}
1611+
1612+
public function testCreatePublicLinkExpireDateInvalidPast() {
1613+
$config = \OC::$server->getConfig();
1614+
1615+
$date = new \DateTime();
1616+
$date->sub(new \DateInterval('P8D'));
1617+
1618+
$_POST['path'] = $this->folder;
1619+
$_POST['shareType'] = \OCP\Share::SHARE_TYPE_LINK;
1620+
$_POST['expireDate'] = $date->format('Y-m-d');
1621+
1622+
$result = \OCA\Files_Sharing\API\Local::createShare([]);
1623+
1624+
$this->assertFalse($result->succeeded());
1625+
$this->assertEquals(404, $result->getStatusCode());
1626+
$this->assertEquals('Cannot set expiration date. Expiration date is in the past', $result->getMeta()['message']);
1627+
1628+
$config->setAppValue('core', 'shareapi_default_expire_date', 'no');
1629+
$config->setAppValue('core', 'shareapi_enforce_expire_date', 'no');
1630+
}
1631+
14901632
}

lib/private/share/share.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,21 @@ public static function shareItem($itemType, $itemSource, $shareType, $shareWith,
649649
$permissions = (int)$permissions & ~\OCP\Constants::PERMISSION_DELETE;
650650
}
651651

652+
//Validate expirationDate
653+
if ($expirationDate !== null) {
654+
try {
655+
/*
656+
* Reuse the validateExpireDate.
657+
* We have to pass time() since the second arg is the time
658+
* the file was shared, since it is not shared yet we just use
659+
* the current time.
660+
*/
661+
$expirationDate = self::validateExpireDate($expirationDate->format('Y-m-d'), time(), $itemType, $itemSource);
662+
} catch (\Exception $e) {
663+
throw new \OC\HintException($e->getMessage(), $e->getMessage(), 404);
664+
}
665+
}
666+
652667
// Verify share type and sharing conditions are met
653668
if ($shareType === self::SHARE_TYPE_USER) {
654669
if ($shareWith == $uidOwner) {

0 commit comments

Comments
 (0)