diff options
Diffstat (limited to 'lib/public/share.php')
-rw-r--r-- | lib/public/share.php | 96 |
1 files changed, 59 insertions, 37 deletions
diff --git a/lib/public/share.php b/lib/public/share.php index da1c0616390..d736871d244 100644 --- a/lib/public/share.php +++ b/lib/public/share.php @@ -20,15 +20,10 @@ */ namespace OCP; -\OC_Hook::connect('OC_User', 'post_deleteUser', 'OCP\Share', 'post_deleteUser'); -\OC_Hook::connect('OC_User', 'post_addToGroup', 'OCP\Share', 'post_addToGroup'); -\OC_Hook::connect('OC_User', 'post_removeFromGroup', 'OCP\Share', 'post_removeFromGroup'); -\OC_Hook::connect('OC_User', 'post_deleteGroup', 'OCP\Share', 'post_deleteGroup'); - /** * This class provides the ability for apps to share their content between users. * Apps must create a backend class that implements OCP\Share_Backend and register it with this class. -* +* * It provides the following hooks: * - post_shared */ @@ -46,17 +41,15 @@ class Share { * Check if permission is granted with And (&) e.g. Check if delete is granted: if ($permissions & PERMISSION_DELETE) * Remove permissions with And (&) and Not (~) e.g. Remove the update permission: $permissions &= ~PERMISSION_UPDATE * Apps are required to handle permissions on their own, this class only stores and manages the permissions of shares + * @see lib/public/constants.php */ - const PERMISSION_CREATE = 4; - const PERMISSION_READ = 1; - const PERMISSION_UPDATE = 2; - const PERMISSION_DELETE = 8; - const PERMISSION_SHARE = 16; const FORMAT_NONE = -1; const FORMAT_STATUSES = -2; const FORMAT_SOURCES = -3; + const TOKEN_LENGTH = 32; // see db_structure.xml + private static $shareTypeUserAndGroups = -1; private static $shareTypeGroupUserUnique = 2; private static $backends = array(); @@ -144,6 +137,20 @@ class Share { } /** + * @brief Get the item shared by a token + * @param string token + * @return Item + */ + public static function getShareByToken($token) { + $query = \OC_DB::prepare('SELECT * FROM `*PREFIX*share` WHERE `token` = ?',1); + $result = $query->execute(array($token)); + if (\OC_DB::isError($result)) { + \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result) . ', token=' . $token, \OC_Log::ERROR); + } + return $result->fetchRow(); + } + + /** * @brief Get the shared items of item type owned by the current user * @param string Item type * @param int Format (optional) Format type must be defined by the backend @@ -172,7 +179,7 @@ class Share { * @param int SHARE_TYPE_USER, SHARE_TYPE_GROUP, or SHARE_TYPE_LINK * @param string User or group the item is being shared with * @param int CRUDS permissions - * @return bool Returns true on success or false on failure + * @return bool|string Returns true on success or false on failure, Returns token on success for links */ public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions) { $uidOwner = \OC_User::getUser(); @@ -234,23 +241,33 @@ class Share { $shareWith['users'] = array_diff(\OC_Group::usersInGroup($group), array($uidOwner)); } else if ($shareType === self::SHARE_TYPE_LINK) { if (\OC_Appconfig::getValue('core', 'shareapi_allow_links', 'yes') == 'yes') { + // when updating a link share if ($checkExists = self::getItems($itemType, $itemSource, self::SHARE_TYPE_LINK, null, $uidOwner, self::FORMAT_NONE, null, 1)) { - // If password is set delete the old link - if (isset($shareWith)) { - self::delete($checkExists['id']); - } else { - $message = 'Sharing '.$itemSource.' failed, because this item is already shared with a link'; - \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); - throw new \Exception($message); - } + // remember old token + $oldToken = $checkExists['token']; + //delete the old share + self::delete($checkExists['id']); } + // Generate hash of password - same method as user passwords if (isset($shareWith)) { $forcePortable = (CRYPT_BLOWFISH != 1); $hasher = new \PasswordHash(8, $forcePortable); $shareWith = $hasher->HashPassword($shareWith.\OC_Config::getValue('passwordsalt', '')); } - return self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions); + + // Generate token + if (isset($oldToken)) { + $token = $oldToken; + } else { + $token = \OC_Util::generate_random_bytes(self::TOKEN_LENGTH); + } + $result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token); + if ($result) { + return $token; + } else { + return false; + } } $message = 'Sharing '.$itemSource.' failed, because sharing with links is not allowed'; \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); @@ -402,7 +419,7 @@ class Share { // Check if permissions were removed if ($item['permissions'] & ~$permissions) { // If share permission is removed all reshares must be deleted - if (($item['permissions'] & self::PERMISSION_SHARE) && (~$permissions & self::PERMISSION_SHARE)) { + if (($item['permissions'] & PERMISSION_SHARE) && (~$permissions & PERMISSION_SHARE)) { self::delete($item['id'], true); } else { $ids = array(); @@ -552,7 +569,7 @@ class Share { $itemTypes = $collectionTypes; } $placeholders = join(',', array_fill(0, count($itemTypes), '?')); - $where .= ' WHERE item_type IN ('.$placeholders.'))'; + $where .= ' WHERE `item_type` IN ('.$placeholders.'))'; $queryArgs = $itemTypes; } else { $where = ' WHERE `item_type` = ?'; @@ -629,7 +646,7 @@ class Share { $queryArgs[] = $item; if ($includeCollections && $collectionTypes) { $placeholders = join(',', array_fill(0, count($collectionTypes), '?')); - $where .= ' OR item_type IN ('.$placeholders.'))'; + $where .= ' OR `item_type` IN ('.$placeholders.'))'; $queryArgs = array_merge($queryArgs, $collectionTypes); } } @@ -658,16 +675,16 @@ class Share { } else { if (isset($uidOwner)) { if ($itemType == 'file' || $itemType == 'folder') { - $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `file_source`, `path`, `permissions`, `stime`, `expiration`'; + $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `file_source`, `path`, `permissions`, `stime`, `expiration`, `token`'; } else { - $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `permissions`, `stime`, `file_source`, `expiration`'; + $select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `permissions`, `stime`, `file_source`, `expiration`, `token`'; } } else { if ($fileDependent) { if (($itemType == 'file' || $itemType == 'folder') && $format == \OC_Share_Backend_File::FORMAT_FILE_APP || $format == \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT) { $select = '`*PREFIX*share`.`id`, `item_type`, `*PREFIX*share`.`parent`, `uid_owner`, `share_type`, `share_with`, `file_source`, `path`, `file_target`, `permissions`, `expiration`, `name`, `ctime`, `mtime`, `mimetype`, `size`, `encrypted`, `versioned`, `writable`'; } else { - $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, `file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`'; + $select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`, `*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`, `file_source`, `path`, `file_target`, `permissions`, `stime`, `expiration`, `token`'; } } else { $select = '*'; @@ -677,6 +694,9 @@ class Share { $root = strlen($root); $query = \OC_DB::prepare('SELECT '.$select.' FROM `*PREFIX*share` '.$where, $queryLimit); $result = $query->execute($queryArgs); + if (\OC_DB::isError($result)) { + \OC_Log::write('OCP\Share', \OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where, \OC_Log::ERROR); + } $items = array(); $targets = array(); while ($row = $result->fetchRow()) { @@ -701,7 +721,7 @@ class Share { $items[$id]['share_with'] = $row['share_with']; } // Switch ids if sharing permission is granted on only one share to ensure correct parent is used if resharing - if (~(int)$items[$id]['permissions'] & self::PERMISSION_SHARE && (int)$row['permissions'] & self::PERMISSION_SHARE) { + if (~(int)$items[$id]['permissions'] & PERMISSION_SHARE && (int)$row['permissions'] & PERMISSION_SHARE) { $items[$row['id']] = $items[$id]; unset($items[$id]); $id = $row['id']; @@ -836,7 +856,7 @@ class Share { * @param bool|array Parent folder target (optional) * @return bool Returns true on success or false on failure */ - private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $parentFolder = null) { + private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $parentFolder = null, $token = null) { $backend = self::getBackend($itemType); // Check if this is a reshare if ($checkReshare = self::getItemSharedWithBySource($itemType, $itemSource, self::FORMAT_NONE, null, true)) { @@ -847,7 +867,7 @@ class Share { throw new \Exception($message); } // Check if share permissions is granted - if ((int)$checkReshare['permissions'] & self::PERMISSION_SHARE) { + if ((int)$checkReshare['permissions'] & PERMISSION_SHARE) { if (~(int)$checkReshare['permissions'] & $permissions) { $message = 'Sharing '.$itemSource.' failed, because the permissions exceed permissions granted to '.$uidOwner; \OC_Log::write('OCP\Share', $message, \OC_Log::ERROR); @@ -893,7 +913,7 @@ class Share { $fileSource = null; } } - $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`) VALUES (?,?,?,?,?,?,?,?,?,?,?)'); + $query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` (`item_type`, `item_source`, `item_target`, `parent`, `share_type`, `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`, `token`) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)'); // Share with a group if ($shareType == self::SHARE_TYPE_GROUP) { $groupItemTarget = self::generateTarget($itemType, $itemSource, $shareType, $shareWith['group'], $uidOwner, $suggestedItemTarget); @@ -914,7 +934,7 @@ class Share { } else { $groupFileTarget = null; } - $query->execute(array($itemType, $itemSource, $groupItemTarget, $parent, $shareType, $shareWith['group'], $uidOwner, $permissions, time(), $fileSource, $groupFileTarget)); + $query->execute(array($itemType, $itemSource, $groupItemTarget, $parent, $shareType, $shareWith['group'], $uidOwner, $permissions, time(), $fileSource, $groupFileTarget, $token)); // Save this id, any extra rows for this group share will need to reference it $parent = \OC_DB::insertid('*PREFIX*share'); // Loop through all users of this group in case we need to add an extra row @@ -948,11 +968,12 @@ class Share { 'permissions' => $permissions, 'fileSource' => $fileSource, 'fileTarget' => $fileTarget, - 'id' => $parent + 'id' => $parent, + 'token' => $token )); // Insert an extra row for the group share if the item or file target is unique for this user if ($itemTarget != $groupItemTarget || (isset($fileSource) && $fileTarget != $groupFileTarget)) { - $query->execute(array($itemType, $itemSource, $itemTarget, $parent, self::$shareTypeGroupUserUnique, $uid, $uidOwner, $permissions, time(), $fileSource, $fileTarget)); + $query->execute(array($itemType, $itemSource, $itemTarget, $parent, self::$shareTypeGroupUserUnique, $uid, $uidOwner, $permissions, time(), $fileSource, $fileTarget, $token)); $id = \OC_DB::insertid('*PREFIX*share'); } } @@ -977,7 +998,7 @@ class Share { } else { $fileTarget = null; } - $query->execute(array($itemType, $itemSource, $itemTarget, $parent, $shareType, $shareWith, $uidOwner, $permissions, time(), $fileSource, $fileTarget)); + $query->execute(array($itemType, $itemSource, $itemTarget, $parent, $shareType, $shareWith, $uidOwner, $permissions, time(), $fileSource, $fileTarget, $token)); $id = \OC_DB::insertid('*PREFIX*share'); \OC_Hook::emit('OCP\Share', 'post_shared', array( 'itemType' => $itemType, @@ -990,7 +1011,8 @@ class Share { 'permissions' => $permissions, 'fileSource' => $fileSource, 'fileTarget' => $fileTarget, - 'id' => $id + 'id' => $id, + 'token' => $token )); if ($parentFolder === true) { $parentFolders['id'] = $id; @@ -1133,7 +1155,7 @@ class Share { $duplicateParent = $query->execute(array($item['item_type'], $item['item_target'], self::SHARE_TYPE_USER, self::SHARE_TYPE_GROUP, self::$shareTypeGroupUserUnique, $item['uid_owner'], $item['parent']))->fetchRow(); if ($duplicateParent) { // Change the parent to the other item id if share permission is granted - if ($duplicateParent['permissions'] & self::PERMISSION_SHARE) { + if ($duplicateParent['permissions'] & PERMISSION_SHARE) { $query = \OC_DB::prepare('UPDATE `*PREFIX*share` SET `parent` = ? WHERE `id` = ?'); $query->execute(array($duplicateParent['id'], $item['id'])); continue; |