* @author Joas Schilling * @author Miguel Prokop * @author Morris Jobke * @author Robin McCorkell * @author Thomas Müller * @author Vincent Petry * * @copyright Copyright (c) 2015, ownCloud, Inc. * @license AGPL-3.0 * * This code is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License, version 3, * along with this program. If not, see * */ namespace OC\Share; use OC\Share\Exceptions\InvalidFederatedCloudIdException; class Helper extends \OC\Share\Constants { /** * Generate a unique target for the item * @param string $itemType * @param string $itemSource * @param int $shareType SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK * @param string $shareWith User or group the item is being shared with * @param string $uidOwner User that is the owner of shared item * @param string $suggestedTarget The suggested target originating from a reshare (optional) * @param int $groupParent The id of the parent group share (optional) * @throws \Exception * @return string Item target */ public static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $suggestedTarget = null, $groupParent = null) { // FIXME: $uidOwner and $groupParent seems to be unused $backend = \OC\Share\Share::getBackend($itemType); if ($shareType === self::SHARE_TYPE_LINK || $shareType === self::SHARE_TYPE_REMOTE) { if (isset($suggestedTarget)) { return $suggestedTarget; } return $backend->generateTarget($itemSource, false); } else { if ($shareType == self::SHARE_TYPE_USER) { // Share with is a user, so set share type to user and groups $shareType = self::$shareTypeUserAndGroups; } // Check if suggested target exists first if (!isset($suggestedTarget)) { $suggestedTarget = $itemSource; } if ($shareType == self::SHARE_TYPE_GROUP) { $target = $backend->generateTarget($suggestedTarget, false); } else { $target = $backend->generateTarget($suggestedTarget, $shareWith); } return $target; } } /** * Delete all reshares and group share children of an item * @param int $parent Id of item to delete * @param bool $excludeParent If true, exclude the parent from the delete (optional) * @param string $uidOwner The user that the parent was shared with (optional) * @param int $newParent new parent for the childrens * @param bool $excludeGroupChildren exclude group children elements */ public static function delete($parent, $excludeParent = false, $uidOwner = null, $newParent = null, $excludeGroupChildren = false) { $ids = array($parent); $deletedItems = array(); $changeParent = array(); $parents = array($parent); while (!empty($parents)) { $parents = "'".implode("','", $parents)."'"; // Check the owner on the first search of reshares, useful for // finding and deleting the reshares by a single user of a group share $params = array(); if (count($ids) == 1 && isset($uidOwner)) { // FIXME: don't concat $parents, use Docrine's PARAM_INT_ARRAY approach $queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, ' . '`item_target`, `file_target`, `parent` ' . 'FROM `*PREFIX*share` ' . 'WHERE `parent` IN ('.$parents.') AND `uid_owner` = ? '; $params[] = $uidOwner; } else { $queryString = 'SELECT `id`, `share_with`, `item_type`, `share_type`, ' . '`item_target`, `file_target`, `parent`, `uid_owner` ' . 'FROM `*PREFIX*share` WHERE `parent` IN ('.$parents.') '; } if ($excludeGroupChildren) { $queryString .= ' AND `share_type` != ?'; $params[] = self::$shareTypeGroupUserUnique; } $query = \OC_DB::prepare($queryString); $result = $query->execute($params); // Reset parents array, only go through loop again if items are found $parents = array(); while ($item = $result->fetchRow()) { $tmpItem = array( 'id' => $item['id'], 'shareWith' => $item['share_with'], 'itemTarget' => $item['item_target'], 'itemType' => $item['item_type'], 'shareType' => (int)$item['share_type'], ); if (isset($item['file_target'])) { $tmpItem['fileTarget'] = $item['file_target']; } // if we have a new parent for the child we remember the child // to update the parent, if not we add it to the list of items // which should be deleted if ($newParent !== null) { $changeParent[] = $item['id']; } else { $deletedItems[] = $tmpItem; $ids[] = $item['id']; $parents[] = $item['id']; } } } if ($excludeParent) { unset($ids[0]); } if (!empty($changeParent)) { $idList = "'".implode("','", $changeParent)."'"; $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` IN ('.$idList.')'); $query->execute(array($newParent)); } if (!empty($ids)) { $idList = "'".implode("','", $ids)."'"; $query = \OC_DB::prepare('DELETE FROM `*PREFIX*share` WHERE `id` IN ('.$idList.')'); $query->execute(); } return $deletedItems; } /** * get default expire settings defined by the admin * @return array contains 'defaultExpireDateSet', 'enforceExpireDate', 'expireAfterDays' */ public static function getDefaultExpireSetting() { $config = \OC::$server->getConfig(); $defaultExpireSettings = array('defaultExpireDateSet' => false); // get default expire settings $defaultExpireDate = $config->getAppValue('core', 'shareapi_default_expire_date', 'no'); if ($defaultExpireDate === 'yes') { $enforceExpireDate = $config->getAppValue('core', 'shareapi_enforce_expire_date', 'no'); $defaultExpireSettings['defaultExpireDateSet'] = true; $defaultExpireSettings['expireAfterDays'] = (int)($config->getAppValue('core', 'shareapi_expire_after_n_days', '7')); $defaultExpireSettings['enforceExpireDate'] = $enforceExpireDate === 'yes' ? true : false; } return $defaultExpireSettings; } public static function calcExpireDate() { $expireAfter = \OC\Share\Share::getExpireInterval() * 24 * 60 * 60; $expireAt = time() + $expireAfter; $date = new \DateTime(); $date->setTimestamp($expireAt); $date->setTime(0, 0, 0); //$dateString = $date->format('Y-m-d') . ' 00:00:00'; return $date; } /** * calculate expire date * @param array $defaultExpireSettings contains 'defaultExpireDateSet', 'enforceExpireDate', 'expireAfterDays' * @param int $creationTime timestamp when the share was created * @param int $userExpireDate expire timestamp set by the user * @return mixed integer timestamp or False */ public static function calculateExpireDate($defaultExpireSettings, $creationTime, $userExpireDate = null) { $expires = false; $defaultExpires = null; if (!empty($defaultExpireSettings['defaultExpireDateSet'])) { $defaultExpires = $creationTime + $defaultExpireSettings['expireAfterDays'] * 86400; } if (isset($userExpireDate)) { // if the admin decided to enforce the default expire date then we only take // the user defined expire date of it is before the default expire date if ($defaultExpires && !empty($defaultExpireSettings['enforceExpireDate'])) { $expires = min($userExpireDate, $defaultExpires); } else { $expires = $userExpireDate; } } else if ($defaultExpires && !empty($defaultExpireSettings['enforceExpireDate'])) { $expires = $defaultExpires; } return $expires; } /** * Strips away a potential file names and trailing slashes: * - http://localhost * - http://localhost/ * - http://localhost/index.php * - http://localhost/index.php/s/{shareToken} * * all return: http://localhost * * @param string $shareWith * @return string */ protected static function fixRemoteURL($remote) { $remote = str_replace('\\', '/', $remote); if ($fileNamePosition = strpos($remote, '/index.php')) { $remote = substr($remote, 0, $fileNamePosition); } $remote = rtrim($remote, '/'); return $remote; } /** * split user and remote from federated cloud id * * @param string $id * @return array * @throws InvalidFederatedCloudIdException */ public static function splitUserRemote($id) { if (strpos($id, '@') === false) { throw new InvalidFederatedCloudIdException('invalid Federated Cloud ID'); } // Find the first character that is not allowed in user names $id = str_replace('\\', '/', $id); $posSlash = strpos($id, '/'); $posColon = strpos($id, ':'); if ($posSlash === false && $posColon === false) { $invalidPos = strlen($id); } else if ($posSlash === false) { $invalidPos = $posColon; } else if ($posColon === false) { $invalidPos = $posSlash; } else { $invalidPos = min($posSlash, $posColon); } // Find the last @ before $invalidPos $pos = $lastAtPos = 0; while ($lastAtPos !== false && $lastAtPos <= $invalidPos) { $pos = $lastAtPos; $lastAtPos = strpos($id, '@', $pos + 1); } if ($pos !== false) { $user = substr($id, 0, $pos); $remote = substr($id, $pos + 1); $remote = self::fixRemoteURL($remote); if (!empty($user) && !empty($remote)) { return array($user, $remote); } } throw new InvalidFederatedCloudIdException('invalid Federated Cloud ID'); } }