diff --git a/core/src/plugins/access.ajxp_conf/class.ajxp_confAccessDriver.php b/core/src/plugins/access.ajxp_conf/class.ajxp_confAccessDriver.php index 6f508e14c4..d77371a5f2 100644 --- a/core/src/plugins/access.ajxp_conf/class.ajxp_confAccessDriver.php +++ b/core/src/plugins/access.ajxp_conf/class.ajxp_confAccessDriver.php @@ -1539,7 +1539,8 @@ public function switchAction($action, $httpVars, $fileVars) case "clear_expired" : - $deleted = ShareCenter::clearExpiredFiles(false); // $this->clearExpiredFiles(); + $shareCenter = AJXP_PluginsService::getInstance()->findPluginById("action.share"); + $deleted = $shareCenter->clearExpiredFiles(false); // $this->clearExpiredFiles(); AJXP_XMLWriter::header(); if (count($deleted)) { AJXP_XMLWriter::sendMessage(sprintf($mess["ajxp_shared.23"], count($deleted).""), null); @@ -2295,8 +2296,9 @@ public function listSharedFiles() $downloadBase = str_replace("\\", "/", $fullUrl.rtrim(str_replace(AJXP_INSTALL_PATH, "", $dlFolder), "/")); } + $shareCenter = AJXP_PluginsService::getInstance()->findPluginById("action.share"); foreach ($files as $file) { - $publicletData = ShareCenter::loadPublicletData(array_shift(explode(".", basename($file)))); + $publicletData = $shareCenter->loadPublicletData(array_shift(explode(".", basename($file)))); if (!is_a($publicletData["REPOSITORY"], "Repository")) { continue; } diff --git a/core/src/plugins/access.ajxp_shared/class.ajxpSharedAccessDriver.php b/core/src/plugins/access.ajxp_shared/class.ajxpSharedAccessDriver.php index 936f8e0af9..62bfe11ae4 100644 --- a/core/src/plugins/access.ajxp_shared/class.ajxpSharedAccessDriver.php +++ b/core/src/plugins/access.ajxp_shared/class.ajxpSharedAccessDriver.php @@ -98,11 +98,12 @@ public function switchAction($action, $httpVars, $fileVars) $selection->initFromHttpVars($httpVars); $files = $selection->getFiles(); AJXP_XMLWriter::header(); + $shareCenter = AJXP_PluginsService::findPluginById("action.share"); foreach ($files as $index => $element) { $element = basename($element); $ar = explode("shared_", $mime); $mime = array_pop($ar); - ShareCenter::deleteSharedElement($mime, $element, $loggedUser); + $shareCenter->deleteSharedElement($mime, $element, $loggedUser); if($mime == "repository") $out = $mess["ajxp_conf.59"]; else if($mime == "user") $out = $mess["ajxp_conf.60"]; else if($mime == "file") $out = $mess["ajxp_shared.13"]; diff --git a/core/src/plugins/access.ajxp_user/class.UserDashboardDriver.php b/core/src/plugins/access.ajxp_user/class.UserDashboardDriver.php index 124f2d2662..9f8885751a 100644 --- a/core/src/plugins/access.ajxp_user/class.UserDashboardDriver.php +++ b/core/src/plugins/access.ajxp_user/class.UserDashboardDriver.php @@ -153,6 +153,7 @@ public function switchAction($action, $httpVars, $fileVars) $files = $selection->getFiles(); AJXP_XMLWriter::header(); $minisites = $this->listSharedFiles("minisites"); + $shareCenter = AJXP_PluginsService::findPluginById("action.share"); foreach ($files as $index => $element) { $element = basename($element); $ar = explode("shared_", $mime); @@ -161,7 +162,7 @@ public function switchAction($action, $httpVars, $fileVars) $mime = "minisite"; $element = $minisites[$element]; } - ShareCenter::deleteSharedElement($mime, $element, $loggedUser); + $shareCenter->deleteSharedElement($mime, $element, $loggedUser); if($mime == "repository" || $mime == "minisite") $out = $mess["ajxp_conf.59"]; else if($mime == "user") $out = $mess["ajxp_conf.60"]; else if($mime == "file") $out = $mess["user_dash.13"]; @@ -173,7 +174,8 @@ public function switchAction($action, $httpVars, $fileVars) case "clear_expired" : - $deleted = ShareCenter::clearExpiredFiles(true); // $this->clearExpiredFiles(); + $shareCenter = AJXP_PluginsService::getInstance()->findPluginById("action.share"); + $deleted = $shareCenter->clearExpiredFiles(true); AJXP_XMLWriter::header(); if (count($deleted)) { AJXP_XMLWriter::sendMessage(sprintf($mess["user_dash.23"], count($deleted).""), null); @@ -237,12 +239,13 @@ public function listSharedFiles($mode = "files") $downloadBase = str_replace("\\", "/", $fullUrl.rtrim(str_replace(AJXP_INSTALL_PATH, "", $dlFolder), "/")); } $minisites = array(); + $shareCenter = AJXP_PluginsService::getInstance()->findPluginById("action.share"); foreach ($files as $file) { $ar = explode(".", basename($file)); $id = array_shift($ar); if($ar[0] != "php") continue; //if(strlen($id) != 32) continue; - $publicletData = ShareCenter::loadPublicletData($id); + $publicletData = $shareCenter->loadPublicletData($id); if($mode == "files"){ if(isSet($publicletData["AJXP_APPLICATION_BASE"]) || isSet($publicletData["TRAVEL_PATH_TO_ROOT"]) || (isset($publicletData["OWNER_ID"]) && $publicletData["OWNER_ID"] != $userId) diff --git a/core/src/plugins/access.fs/class.fsAccessDriver.php b/core/src/plugins/access.fs/class.fsAccessDriver.php index 84661efa30..afba38891d 100644 --- a/core/src/plugins/access.fs/class.fsAccessDriver.php +++ b/core/src/plugins/access.fs/class.fsAccessDriver.php @@ -1869,6 +1869,7 @@ public function makeZip ($src, $dest, $basedir) public function recursivePurge($dirName, $hardPurgeTime, $softPurgeTime = 0) { $handle=opendir($dirName); + $shareCenter = AJXP_PluginsService::findPluginById("action.share"); while (false !== ($entry = readdir($handle))) { if ($entry == "" || $entry == ".." || AJXP_Utils::isHidden($entry) ) { continue; @@ -1879,7 +1880,7 @@ public function recursivePurge($dirName, $hardPurgeTime, $softPurgeTime = 0) if ($hardPurgeTime > 0 && $docAge > $hardPurgeTime) { $this->purge($fileName); } elseif ($softPurgeTime > 0 && $docAge > $softPurgeTime) { - if(!ShareCenter::isShared(new AJXP_Node($fileName))) { + if($shareCenter !== false && $shareCenter->isShared(new AJXP_Node($fileName))) { $this->purge($fileName); } } diff --git a/core/src/plugins/action.share/class.ShareCenter.php b/core/src/plugins/action.share/class.ShareCenter.php index 03270f07bc..d8688724c3 100644 --- a/core/src/plugins/action.share/class.ShareCenter.php +++ b/core/src/plugins/action.share/class.ShareCenter.php @@ -21,8 +21,6 @@ defined('AJXP_EXEC') or die( 'Access not allowed'); -require_once("class.PublicletCounter.php"); - /** * @package AjaXplorer_Plugins * @subpackage Action @@ -40,6 +38,10 @@ class ShareCenter extends AJXP_Plugin private $urlBase; private $baseProtocol; + /** + * @var ShareStore + */ + private $shareStore; /** * @var MetaStoreProvider */ @@ -96,6 +98,30 @@ public function init($options) } } + /** + * @return ShareStore + */ + private function getShareStore(){ + if(!isSet($this->shareStore)){ + require_once("class.ShareStore.php"); + $hMin = 32; + if(isSet($this->repository)){ + $hMin = $this->getFilteredOption("HASH_MIN_LENGTH", $this->repository->getId()); + } + $this->shareStore = new ShareStore( + ConfService::getCoreConf("PUBLIC_DOWNLOAD_FOLDER"), + $hMin + ); + } + return $this->shareStore; + } + + public function preProcessDownload($action, &$httpVars, &$fileVars){ + if(isSet($_SESSION["CURRENT_MINISITE"])){ + $this->logDebug(__FUNCTION__, "Do something here!"); + } + } + public function switchAction($action, $httpVars, $fileVars) { if (!isSet($this->accessDriver)) { @@ -299,7 +325,7 @@ public function switchAction($action, $httpVars, $fileVars) foreach ($elements as $element => $elementData) { if(!is_array($elementData)) $elementData = array(); - $pData = self::loadPublicletData($element); + $pData = $this->getShareStore()->loadShare($element); if (!count($pData)) { continue; } @@ -326,7 +352,7 @@ public function switchAction($action, $httpVars, $fileVars) $jsonData[] = array_merge(array( "element_id" => $element, "publiclet_link" => $link, - "download_counter" => PublicletCounter::getCount($element), + "download_counter" => $this->getShareStore()->getCurrentDownloadCounter($element), "download_limit" => $pData["DOWNLOAD_LIMIT"], "expire_time" => ($pData["EXPIRE_TIME"]!=0?date($messages["date_format"], $pData["EXPIRE_TIME"]):0), "has_password" => (!empty($pData["PASSWORD"])), @@ -336,7 +362,7 @@ public function switchAction($action, $httpVars, $fileVars) } } else if ($elementType == "repository" || isSet($metadata["minisite"])) { if (isSet($metadata["minisite"])) { - $minisiteData = self::loadPublicletData($metadata["element"]); + $minisiteData = $this->getShareStore()->loadShare($metadata["element"]); $repoId = $minisiteData["REPOSITORY"]; $minisiteIsPublic = isSet($minisiteData["PRELOG_USER"]); $dlDisabled = isSet($minisiteData["DOWNLOAD_DISABLED"]); @@ -415,7 +441,7 @@ public function switchAction($action, $httpVars, $fileVars) if(count($metadata["element"]) > 0) $updateMeta = true; } } - self::deleteSharedElement($eType, $elementId, AuthService::getLoggedUser()); + $this->getShareStore()->deleteShare($eType, $elementId, AuthService::getLoggedUser()); if ($updateMeta) { $ajxpNode->setMetadata("ajxp_shared", $metadata, true, AJXP_METADATA_SCOPE_REPOSITORY, true); } else { @@ -436,7 +462,7 @@ public function switchAction($action, $httpVars, $fileVars) AJXP_METADATA_SCOPE_REPOSITORY ); if (isSet($metadata["element"][$httpVars["element_id"]])) { - PublicletCounter::reset($httpVars["element_id"]); + $this->getShareStore()->resetDownloadCounter($httpVars["element_id"]); } break; @@ -487,7 +513,7 @@ public function nodeSharedMetadata(&$ajxpNode) if (is_array($metadata["element"])) { $updateMeta = false; foreach ($metadata["element"] as $elementId => $elementData) { - if (!self::sharedElementExists($eType, $elementId)) { + if (!$this->getShareStore()->shareExists($eType, $elementId)) { unset($metadata["element"][$elementId]); $updateMeta = true; return; @@ -505,7 +531,7 @@ public function nodeSharedMetadata(&$ajxpNode) } } } else { - if (!self::sharedElementExists($eType, $metadata["element"])) { + if (!$this->getShareStore()->shareExists($eType, $metadata["element"])) { $ajxpNode->removeMetadata("ajxp_shared", true, AJXP_METADATA_SCOPE_REPOSITORY, true); return; } @@ -524,14 +550,14 @@ public function nodeSharedMetadata(&$ajxpNode) * @param AJXP_Node $ajxpNode * @return boolean */ - public static function isShared($ajxpNode) + public function isShared($ajxpNode) { $metadata = $ajxpNode->retrieveMetadata("ajxp_shared",true); if (is_array($metadata) && is_array($metadata["element"])) { $eType = $ajxpNode->isLeaf()?"file":"repository"; if(isSet($metadata["minisite"])) $eType = "minisite"; foreach ($metadata["element"] as $elementId => $elementData) { - if (self::sharedElementExists($eType, $elementId)) { + if ($this->getShareStore()->shareExists($eType, $elementId)) { return true; } } @@ -554,7 +580,7 @@ private function findMirrorNodesInShares($node, $direction){ if(is_string($metadata["element"])){ $wsId = $metadata["element"]; if(isSet($metadata["minisite"])){ - $minisiteData = self::loadPublicletData($metadata["element"]); + $minisiteData = $this->getShareStore()->loadShare($metadata["element"]); $wsId = $minisiteData["REPOSITORY"]; } $sharedNode = $metadata["SOURCE_NODE"]; @@ -712,7 +738,7 @@ public function updateNodeSharedData($oldNode/*, $newNode = null, $copy = false* $elementIds[]= $metadata["element"]; } foreach ($elementIds as $elementId) { - self::deleteSharedElement( + $this->getShareStore()->deleteShare( $type, $elementId, AuthService::getLoggedUser() @@ -781,25 +807,14 @@ public function writePubliclet(&$data, $accessDriver, $repository) if ($data["ACTION"] == "") $data["ACTION"] = "download"; // Create a random key $data["FINAL_KEY"] = md5(mt_rand().time()); - // Cypher the data with a random key - $outputData = serialize($data); - // Hash the data to make sure it wasn't modified - $hash = $this->computeHash($outputData, $downloadFolder); // md5($outputData); - - $outputData = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $hash, $outputData, MCRYPT_MODE_ECB)); - $fileData = "<"."?"."php \n". - ' require_once("'.str_replace("\\", "/", AJXP_INSTALL_PATH).'/publicLet.inc.php"); '."\n". - ' $id = str_replace(".php", "", basename(__FILE__)); '."\n". // Not using "" as php would replace $ inside - ' $cypheredData = base64_decode("'.$outputData.'"); '."\n". - ' $inputData = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $id, $cypheredData, MCRYPT_MODE_ECB), "\0"); '."\n". - ' if (!ShareCenter::checkHash($inputData, $id)) { header("HTTP/1.0 401 Not allowed, script was modified"); exit(); } '."\n". - ' // Ok extract the data '."\n". - ' $data = unserialize($inputData); ShareCenter::loadPubliclet($data); '; - if (@file_put_contents($downloadFolder."/".$hash.".php", $fileData) === FALSE) { - return "Can't write to PUBLIC URL"; - } - @chmod($downloadFolder."/".$hash.".php", 0755); - PublicletCounter::reset($hash); + + try{ + $hash = $this->getShareStore()->storeShare($data, "publiclet"); + }catch(Exception $e){ + return $e->getMessage(); + } + + $this->getShareStore()->resetDownloadCounter($hash); $url = $this->buildPublicletLink($hash); $this->logInfo("New Share", array( "file" => "'".$copy->display.":/".$data['FILE_PATH']."'", @@ -818,41 +833,6 @@ public function writePubliclet(&$data, $accessDriver, $repository) return array($hash, $url); } - /** - * Computes a short form of the hash, checking if it already exists in the folder, - * in which case it increases the hashlength until there is no collision. - * @static - * @param String $outputData Serialized data - * @param String|null $checkInFolder Path to folder - * @return string - */ - public function computeHash($outputData, $checkInFolder = null) - { - $length = $this->getFilteredOption("HASH_MIN_LENGTH", $this->repository->getId()); - $full = md5($outputData); - $starter = substr($full, 0, $length); - if ($checkInFolder != null) { - while (file_exists($checkInFolder.DIRECTORY_SEPARATOR.$starter.".php")) { - $length ++; - $starter = substr($full, 0, $length); - } - } - return $starter; - } - - /** - * Check if the hash seems to correspond to the serialized data. - * @static - * @param String $outputData serialized data - * @param String $hash Id to check - * @return bool - */ - public static function checkHash($outputData, $hash) - { - $full = md5($outputData); - return (!empty($hash) && strpos($full, $hash."") === 0); - } - public function buildPublicDlURL() { $downloadFolder = ConfService::getCoreConf("PUBLIC_DOWNLOAD_FOLDER"); @@ -970,6 +950,7 @@ public static function loadMinisite($data) $_SESSION["PENDING_FOLDER"] = "/"; $html = str_replace("AJXP_PRELOGED_USER", "", $html); } + $_SESSION["CURRENT_MINISITE"] = true; if (isSet($_GET["lang"])) { $loggedUser = &AuthService::getLoggedUser(); if ($loggedUser != null) { @@ -990,9 +971,13 @@ public static function loadMinisite($data) echo($html); } - private static function deleteExpiredPubliclet($elementId, $data){ + public static function loadShareByHash($hash){ + AJXP_Logger::debug(__CLASS__, __FUNCTION__, "Do something"); + } - if(AuthService::getLoggedUser()->getId() != $data["OWNER_ID"]){ + private function deleteExpiredPubliclet($elementId, $data){ + + if(AuthService::getLoggedUser() == null || AuthService::getLoggedUser()->getId() != $data["OWNER_ID"]){ AuthService::logUser($data["OWNER_ID"], "", true); } $repoObject = $data["REPOSITORY"]; @@ -1006,7 +991,7 @@ private static function deleteExpiredPubliclet($elementId, $data){ AJXP_METADATA_SCOPE_REPOSITORY, true ); - self::deleteSharedElement("file", $elementId, AuthService::getLoggedUser()); + $this->getShareStore()->deleteShare("file", $elementId, AuthService::getLoggedUser()); if (count($metadata)) { $updateMeta = false; if (is_array($metadata["element"]) && isSet($metadata["element"][$elementId])) { @@ -1035,20 +1020,6 @@ public static function loadPubliclet($data) $u = parse_url($_SERVER["REQUEST_URI"]); $shortHash = pathinfo(basename($u["path"]), PATHINFO_FILENAME); - if ( ($data["EXPIRE_TIME"] && time() > $data["EXPIRE_TIME"]) || - ($data["DOWNLOAD_LIMIT"] && $data["DOWNLOAD_LIMIT"]> 0 && $data["DOWNLOAD_LIMIT"] <= PublicletCounter::getCount($shortHash)) ) - { - // Remove the publiclet, it's done - if (strstr(realpath($_SERVER["SCRIPT_FILENAME"]),realpath(ConfService::getCoreConf("PUBLIC_DOWNLOAD_FOLDER"))) !== FALSE) { - - self::deleteExpiredPubliclet($shortHash, $data); - } - - //echo "Link is expired, sorry."; - header("HTTP/1.0 404 Not Found"); - echo '404 File not found'; - exit(); - } // Load language messages $language = ConfService::getLanguage(); if (isSet($_GET["lang"])) { @@ -1065,6 +1036,23 @@ public static function loadPubliclet($data) $AJXP_LINK_HAS_PASSWORD = false; $AJXP_LINK_BASENAME = SystemTextEncoding::toUTF8(basename($data["FILE_PATH"])); AJXP_PluginsService::getInstance()->initActivePlugins(); + + $shareCenter = AJXP_PluginsService::findPluginById("action.share"); + + if ($shareCenter->getShareStore()->isShareExpired($shortHash, $data)) + { + // Remove the publiclet, it's done + if (strstr(realpath($_SERVER["SCRIPT_FILENAME"]),realpath(ConfService::getCoreConf("PUBLIC_DOWNLOAD_FOLDER"))) !== FALSE) { + $shareCenter->deleteExpiredPubliclet($shortHash, $data); + } + + //echo "Link is expired, sorry."; + header("HTTP/1.0 404 Not Found"); + echo '404 File not found'; + exit(); + } + + $customs = array("title", "legend", "legend_pass", "background_attributes_1", "background_attributes_2", "background_attributes_3", "text_color", "background_color", "textshadow_color"); $images = array("button", "background_1", "background_2", "background_3"); $shareCenter = AJXP_PluginsService::findPlugin("action", "share"); @@ -1125,7 +1113,7 @@ public static function loadPubliclet($data) $driver->loadManifest(); //$hash = md5(serialize($data)); - PublicletCounter::increment($shortHash); + $shareCenter->getShareStore()->incrementDownloadCounter($shortHash); //AuthService::logUser($data["OWNER_ID"], "", true); AuthService::logTemporaryUser($data["OWNER_ID"], $shortHash); @@ -1306,22 +1294,11 @@ public function createSharedMinisite($httpVars, $repository, $accessDriver) $data["AJXP_TEMPLATE_NAME"] = $httpVars["minisite_layout"]; } - $outputData = serialize($data); - $hash = self::computeHash($outputData, $downloadFolder); - - $outputData = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $hash, $outputData, MCRYPT_MODE_ECB)); - $fileData = "<"."?"."php \n". - ' require_once("'.str_replace("\\", "/", AJXP_INSTALL_PATH).'/publicLet.inc.php"); '."\n". - ' $id = str_replace(".php", "", basename(__FILE__)); '."\n". // Not using "" as php would replace $ inside - ' $cypheredData = base64_decode("'.$outputData.'"); '."\n". - ' $inputData = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $id, $cypheredData, MCRYPT_MODE_ECB), "\0"); '."\n". - ' if (!ShareCenter::checkHash($inputData, $id)) { header("HTTP/1.0 401 Not allowed, script was modified"); exit(); } '."\n". - ' // Ok extract the data '."\n". - ' $data = unserialize($inputData); ShareCenter::loadMinisite($data); '; - if (@file_put_contents($downloadFolder."/".$hash.".php", $fileData) === FALSE) { - return "Can't write to PUBLIC URL"; + try{ + $hash = $this->getShareStore()->storeShare($data); + }catch(Exception $e){ + return $e->getMessage(); } - @chmod($downloadFolder."/".$hash.".php", 0755); $url = $this->buildPublicletLink($hash); AJXP_Controller::applyHook("node.share.create", array( @@ -1635,100 +1612,22 @@ public function createSharedRepository($httpVars, $repository, $accessDriver, $u /** - * @static * @param String $type * @param String $element * @param AbstractAjxpUser $loggedUser * @throws Exception */ - public static function deleteSharedElement($type, $element, $loggedUser) + public function deleteSharedElement($type, $element, $loggedUser) { - $mess = ConfService::getMessages(); - AJXP_Logger::debug(__CLASS__, __FILE__, "Deleting shared element ".$type."-".$element); - if ($type == "repository") { - $repo = ConfService::getRepositoryById($element); - if($repo == null) return; - if (!$repo->hasOwner() || $repo->getOwner() != $loggedUser->getId()) { - throw new Exception($mess["ajxp_shared.12"]); - } else { - $res = ConfService::deleteRepository($element); - if ($res == -1) { - throw new Exception($mess["ajxp_conf.51"]); - } - } - } else if ($type == "minisite") { - $minisiteData = self::loadPublicletData($element); - $repoId = $minisiteData["REPOSITORY"]; - $repo = ConfService::getRepositoryById($repoId); - if ($repo == null) { - return false; - } - if (!$repo->hasOwner() || $repo->getOwner() != $loggedUser->getId()) { - throw new Exception($mess["ajxp_shared.12"]); - } else { - $res = ConfService::deleteRepository($repoId); - if ($res == -1) { - throw new Exception($mess["ajxp_conf.51"]); - } - // Silently delete corresponding role if it exists - AuthService::deleteRole("AJXP_SHARED-".$repoId); - // If guest user created, remove it now. - if (isSet($minisiteData["PRELOG_USER"])) { - AuthService::deleteUser($minisiteData["PRELOG_USER"]); - } - unlink($minisiteData["PUBLICLET_PATH"]); - } - } else if ($type == "user") { - $confDriver = ConfService::getConfStorageImpl(); - $object = $confDriver->createUserObject($element); - if (!$object->hasParent() || $object->getParent() != $loggedUser->getId()) { - throw new Exception($mess["ajxp_shared.12"]); - } else { - AuthService::deleteUser($element); - } - } else if ($type == "file") { - $publicletData = self::loadPublicletData($element); - if (isSet($publicletData["OWNER_ID"]) && $publicletData["OWNER_ID"] == $loggedUser->getId()) { - PublicletCounter::delete($element); - unlink($publicletData["PUBLICLET_PATH"]); - } else { - throw new Exception($mess["ajxp_shared.12"]); - } - } - } - - public static function sharedElementExists($type, $element) - { - if ($type == "repository") { - return (ConfService::getRepositoryById($element) != null); - } else if ($type == "file" || $type == "minisite") { - $dlFolder = ConfService::getCoreConf("PUBLIC_DOWNLOAD_FOLDER"); - return is_file($dlFolder."/".$element.".php"); - } + $this->getShareStore()->deleteShare($type, $element, $loggedUser); } - - public static function loadPublicletData($id) + public function loadPublicletData($id) { - $dlFolder = ConfService::getCoreConf("PUBLIC_DOWNLOAD_FOLDER"); - $file = $dlFolder."/".$id.".php"; - if(!is_file($file)) return array(); - $lines = file($file); - $inputData = ''; - $code = $lines[3] . $lines[4] . $lines[5]; - eval($code); - if(empty($inputData)) return false; - $dataModified = self::checkHash($inputData, $id); //(md5($inputData) != $id); - $publicletData = unserialize($inputData); - $publicletData["SECURITY_MODIFIED"] = $dataModified; - if (!isSet($publicletData["REPOSITORY"])) { - $publicletData["DOWNLOAD_COUNT"] = PublicletCounter::getCount($id); - } - $publicletData["PUBLICLET_PATH"] = $file; - return $publicletData; + return $this->getShareStore()->loadShare($id); } - public static function clearExpiredFiles($currentUser = true) + public function clearExpiredFiles($currentUser = true) { $files = glob(ConfService::getCoreConf("PUBLIC_DOWNLOAD_FOLDER")."/*.php"); if($currentUser){ @@ -1740,9 +1639,10 @@ public static function clearExpiredFiles($currentUser = true) $deleted = array(); $switchBackToOriginal = false; foreach ($files as $file) { + if(basename($file) == "share.php") continue; $ar = explode(".", basename($file)); $id = array_shift($ar); - $publicletData = self::loadPublicletData($id); + $publicletData = $this->getShareStore()->loadShare($id); if($publicletData === false) continue; if ($currentUser && ( !isSet($publicletData["OWNER_ID"]) || $publicletData["OWNER_ID"] != $userId )) { continue; @@ -1750,7 +1650,7 @@ public static function clearExpiredFiles($currentUser = true) if( (isSet($publicletData["EXPIRE_TIME"]) && is_numeric($publicletData["EXPIRE_TIME"]) && $publicletData["EXPIRE_TIME"] > 0 && $publicletData["EXPIRE_TIME"] < time()) || (isSet($publicletData["DOWNLOAD_LIMIT"]) && $publicletData["DOWNLOAD_LIMIT"] > 0 && $publicletData["DOWNLOAD_LIMIT"] <= $publicletData["DOWNLOAD_COUNT"]) ) { if(!$currentUser) $switchBackToOriginal = true; - self::deleteExpiredPubliclet($id, $publicletData); + $this->deleteExpiredPubliclet($id, $publicletData); $deleted[] = $publicletData["FILE_PATH"]; } @@ -1766,4 +1666,19 @@ public static function currentContextIsLinkDownload(){ return (isSet($_GET["dl"]) && isSet($_GET["dl"]) == "true"); } + /** + * Check if the hash seems to correspond to the serialized data. + * Kept there only for backward compatibility + * @static + * @param String $outputData serialized data + * @param String $hash Id to check + * @return bool + */ + public static function checkHash($outputData, $hash) + { + $full = md5($outputData); + return (!empty($hash) && strpos($full, $hash."") === 0); + } + + } diff --git a/core/src/plugins/action.share/class.ShareStore.php b/core/src/plugins/action.share/class.ShareStore.php new file mode 100644 index 0000000000..1731d41086 --- /dev/null +++ b/core/src/plugins/action.share/class.ShareStore.php @@ -0,0 +1,222 @@ + + * This file is part of Pydio. + * + * Pydio is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Pydio 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 + * along with Pydio. If not, see . + * + * The latest code can be found at . + */ + +defined('AJXP_EXEC') or die( 'Access not allowed'); + +require_once("class.PublicletCounter.php"); + +class ShareStore { + + var $slqSupported = false; + var $downloadFolder; + var $hashMinLength; + + public function __construct($downloadFolder, $hashMinLength = 32){ + $this->downloadFolder = $downloadFolder; + $this->hashMinLength = $hashMinLength; + $storage = ConfService::getConfStorageImpl(); + } + + /** + * @param Array $shareData + * @param string $type + * @return string $hash + * @throws Exception + */ + public function storeShare($shareData, $type="minisite"){ + + $data = serialize($shareData); + $hash = $this->computeHash($data, $this->downloadFolder); + $loader = 'ShareCenter::loadMinisite($data);'; + if($type == "publiclet"){ + $loader = 'ShareCenter::loadPubliclet($data);'; + } + + $outputData = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $hash, $data, MCRYPT_MODE_ECB)); + $fileData = "<"."?"."php \n". + ' require_once("'.str_replace("\\", "/", AJXP_INSTALL_PATH).'/publicLet.inc.php"); '."\n". + ' $id = str_replace(".php", "", basename(__FILE__)); '."\n". // Not using "" as php would replace $ inside + ' $cypheredData = base64_decode("'.$outputData.'"); '."\n". + ' $inputData = trim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $id, $cypheredData, MCRYPT_MODE_ECB), "\0"); '."\n". + ' if (!ShareCenter::checkHash($inputData, $id)) { header("HTTP/1.0 401 Not allowed, script was modified"); exit(); } '."\n". + ' // Ok extract the data '."\n". + ' $data = unserialize($inputData); '.$loader; + if (@file_put_contents($this->downloadFolder."/".$hash.".php", $fileData) === FALSE) { + throw new Exception("Can't write to PUBLIC URL"); + } + @chmod($this->downloadFolder."/".$hash.".php", 0755); + return $hash; + + } + + public function loadShare($hash){ + + $dlFolder = $this->downloadFolder; + $file = $dlFolder."/".$hash.".php"; + if(!is_file($file)) return array(); + $lines = file($file); + $inputData = ''; + // Necessary for the eval + $id = $hash; + $code = $lines[3] . $lines[4] . $lines[5]; + eval($code); + if(empty($inputData)) return false; + $dataModified = $this->checkHash($inputData, $hash); //(md5($inputData) != $id); + $publicletData = unserialize($inputData); + $publicletData["SECURITY_MODIFIED"] = $dataModified; + if (!isSet($publicletData["REPOSITORY"])) { + $publicletData["DOWNLOAD_COUNT"] = PublicletCounter::getCount($hash); + } + $publicletData["PUBLICLET_PATH"] = $file; + return $publicletData; + + } + + /** + * @param String $type + * @param String $element + * @param AbstractAjxpUser $loggedUser + * @throws Exception + */ + public function deleteShare($type, $element, $loggedUser) + { + $mess = ConfService::getMessages(); + $shareCenter = AJXP_PluginsService::getInstance()->findPluginById("action.share"); + AJXP_Logger::debug(__CLASS__, __FILE__, "Deleting shared element ".$type."-".$element); + if ($type == "repository") { + $repo = ConfService::getRepositoryById($element); + if($repo == null) return; + if (!$repo->hasOwner() || $repo->getOwner() != $loggedUser->getId()) { + throw new Exception($mess["ajxp_shared.12"]); + } else { + $res = ConfService::deleteRepository($element); + if ($res == -1) { + throw new Exception($mess["ajxp_conf.51"]); + } + } + } else if ($type == "minisite") { + $minisiteData = $this->loadShare($element); + $repoId = $minisiteData["REPOSITORY"]; + $repo = ConfService::getRepositoryById($repoId); + if ($repo == null) { + return false; + } + if (!$repo->hasOwner() || $repo->getOwner() != $loggedUser->getId()) { + throw new Exception($mess["ajxp_shared.12"]); + } else { + $res = ConfService::deleteRepository($repoId); + if ($res == -1) { + throw new Exception($mess["ajxp_conf.51"]); + } + // Silently delete corresponding role if it exists + AuthService::deleteRole("AJXP_SHARED-".$repoId); + // If guest user created, remove it now. + if (isSet($minisiteData["PRELOG_USER"])) { + AuthService::deleteUser($minisiteData["PRELOG_USER"]); + } + unlink($minisiteData["PUBLICLET_PATH"]); + } + } else if ($type == "user") { + $confDriver = ConfService::getConfStorageImpl(); + $object = $confDriver->createUserObject($element); + if (!$object->hasParent() || $object->getParent() != $loggedUser->getId()) { + throw new Exception($mess["ajxp_shared.12"]); + } else { + AuthService::deleteUser($element); + } + } else if ($type == "file") { + $publicletData = $this->loadShare($element); + if (isSet($publicletData["OWNER_ID"]) && $publicletData["OWNER_ID"] == $loggedUser->getId()) { + PublicletCounter::delete($element); + unlink($publicletData["PUBLICLET_PATH"]); + } else { + throw new Exception($mess["ajxp_shared.12"]); + } + } + } + + + public function shareExists($type, $element) + { + if ($type == "repository") { + return (ConfService::getRepositoryById($element) != null); + } else if ($type == "file" || $type == "minisite") { + return is_file($this->downloadFolder."/".$element.".php"); + } + } + + + public function getCurrentDownloadCounter($hash){ + return PublicletCounter::getCount($hash); + } + + public function incrementDownloadCounter($hash){ + PublicletCounter::increment($hash); + } + + public function resetDownloadCounter($hash){ + PublicletCounter::reset($hash); + } + + public function isShareExpired($hash, $data){ + return ($data["EXPIRE_TIME"] && time() > $data["EXPIRE_TIME"]) || + ($data["DOWNLOAD_LIMIT"] && $data["DOWNLOAD_LIMIT"]> 0 && $data["DOWNLOAD_LIMIT"] <= $this->getCurrentDownloadCounter($hash)); + } + + + + /** + * Computes a short form of the hash, checking if it already exists in the folder, + * in which case it increases the hashlength until there is no collision. + * @static + * @param String $outputData Serialized data + * @param String|null $checkInFolder Path to folder + * @return string + */ + private function computeHash($outputData, $checkInFolder = null) + { + $length = $this->hashMinLength; + $full = md5($outputData); + $starter = substr($full, 0, $length); + if ($checkInFolder != null) { + while (file_exists($checkInFolder.DIRECTORY_SEPARATOR.$starter.".php")) { + $length ++; + $starter = substr($full, 0, $length); + } + } + return $starter; + } + + /** + * Check if the hash seems to correspond to the serialized data. + * @static + * @param String $outputData serialized data + * @param String $hash Id to check + * @return bool + */ + private function checkHash($outputData, $hash) + { + $full = md5($outputData); + return (!empty($hash) && strpos($full, $hash."") === 0); + } + + +} \ No newline at end of file