diff --git a/htdocs/core/ajax/ajaxdirpreview.php b/htdocs/core/ajax/ajaxdirpreview.php index 203bd71e645..2607002dff3 100644 --- a/htdocs/core/ajax/ajaxdirpreview.php +++ b/htdocs/core/ajax/ajaxdirpreview.php @@ -89,9 +89,7 @@ else // For no ajax call if (empty($url)) $url=DOL_URL_ROOT.'/ecm/index.php'; // Load traductions files -$langs->load("ecm"); -$langs->load("companies"); -$langs->load("other"); +$langs->loadLangs(array("ecm","companies","other")); // Security check if ($user->societe_id > 0) $socid = $user->societe_id; diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 1ae79e0c8fe..4bffc579a8c 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -553,6 +553,90 @@ abstract class CommonObject return $out; } + /** + * Return the link of last main doc file for direct public download. + * + * @param string $modulepart Module related to document + * @param int $initsharekey Init the share key if it was not yet defined + * @return string Link or empty string if there is no download link + */ + function getLastMainDocLink($modulepart, $initsharekey=0) + { + global $user, $dolibarr_main_url_root; + + if (empty($this->last_main_doc)) + { + return ''; // No known last doc + } + + include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; + $ecmfile=new EcmFiles($this->db); + $result = $ecmfile->fetch(0, '', $this->last_main_doc); + if ($result < 0) + { + $this->error = $ecmfile->error; + $this->errors = $ecmfile->errors; + return -1; + } + + if (empty($ecmfile->id)) + { + // Add entry into index + if ($initsharekey) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; + // TODO We can't, we dont' have full path of file, only last_main_doc adn ->element, so we must rebuild full path first + /* + $ecmfile->filepath = $rel_dir; + $ecmfile->filename = $filename; + $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content + $ecmfile->fullpath_orig = ''; + $ecmfile->gen_or_uploaded = 'generated'; + $ecmfile->description = ''; // indexed content + $ecmfile->keyword = ''; // keyword content + $ecmfile->share = getRandomPassword(true); + $result = $ecmfile->create($user); + if ($result < 0) + { + $this->error = $ecmfile->error; + $this->errors = $ecmfile->errors; + } + */ + } + else return ''; + } + elseif (empty($ecmfile->share)) + { + // Add entry into index + if ($initsharekey) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; + $ecmfile->share = getRandomPassword(true); + $ecmfile->update($user); + } + else return ''; + } + + // Define $urlwithroot + $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($dolibarr_main_url_root)); + $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file + //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current + + $forcedownload=1; + $rellink='/document.php?modulepart='.$modulepart; + if ($forcedownload) $rellink.='&attachment=1'; + if (! empty($ecmfile->entity)) $rellink.='&entity='.$ecmfile->entity; + //$rellink.='&file='.urlencode($filepath); // No need of name of file for public link, we will use the hash + $fulllink=$urlwithroot.$rellink; + //if (! empty($object->ref)) $fulllink.='&hashn='.$object->ref; // Hash of file path + //elseif (! empty($object->label)) $fulllink.='&hashc='.$object->label; // Hash of file content + if (! empty($ecmfile->share)) $fulllink.='&hashp='.$ecmfile->share; // Hash for public share + + // Here $ecmfile->share is defined + return $fulllink; + } + + /** * Add a link between element $this->element and a contact * @@ -4120,6 +4204,7 @@ abstract class CommonObject } else { + $ecmfile->entity = $conf->entity; $ecmfile->filepath = $rel_dir; $ecmfile->filename = $filename; $ecmfile->label = md5_file(dol_osencode($destfull)); // hash of file content diff --git a/htdocs/document.php b/htdocs/document.php index a0b764882f8..42ad848a0d7 100644 --- a/htdocs/document.php +++ b/htdocs/document.php @@ -31,12 +31,18 @@ */ define('NOTOKENRENEWAL',1); // Disables token renewal -// Pour autre que bittorrent, on charge environnement + info issus de logon (comme le user) +// For bittorent link, we don't need to load/check we are into a login session if (isset($_GET["modulepart"]) && $_GET["modulepart"] == 'bittorrent' && ! defined("NOLOGIN")) { define("NOLOGIN",1); define("NOCSRFCHECK",1); // We accept to go on this page from external web site. } +// For direct external download link, we don't need to load/check we are into a login session +if (isset($_GET["hashp"]) && ! defined("NOLOGIN")) +{ + define("NOLOGIN",1); + define("NOCSRFCHECK",1); // We accept to go on this page from external web site. +} if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1'); if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1'); if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1'); @@ -111,21 +117,23 @@ if (! empty($hashp)) $result = $ecmfile->fetch(0, '', '', '', $hashp); if ($result > 0) { - $tmp = explode('/', $ecmfile->filepath, 2); // $ecmfile->filepatch is relative to document directory + $tmp = explode('/', $ecmfile->filepath, 2); // $ecmfile->filepath is relative to document directory $moduleparttocheck = $tmp[0]; if ($moduleparttocheck == $modulepart) { + // We remove first level of directory $original_file = (($tmp[1]?$tmp[1].'/':'').$ecmfile->filename); // this is relative to module dir //var_dump($original_file); exit; } else { - accessforbidden('Bad link. File owns to another module part.',0,0,1); + accessforbidden('Bad link. File is from another module part.',0,0,1); } } else { - accessforbidden('Bad link. File was not found or sharing attribute removed recently.',0,0,1); + $langs->load("errors"); + accessforbidden($langs->trans("ErrorFileNotFoundWithSharedLink"),0,0,1); } } @@ -138,30 +146,38 @@ $refname=basename(dirname($original_file)."/"); // Security check if (empty($modulepart)) accessforbidden('Bad value for parameter modulepart'); + $check_access = dol_check_secure_access_document($modulepart, $original_file, $entity, $refname); $accessallowed = $check_access['accessallowed']; $sqlprotectagainstexternals = $check_access['sqlprotectagainstexternals']; $fullpath_original_file = $check_access['original_file']; // $fullpath_original_file is now a full path name -// Basic protection (against external users only) -if ($user->societe_id > 0) +if (! empty($hashp)) { - if ($sqlprotectagainstexternals) + $accessallowed = 1; // When using hashp, link is public so we force $accessallowed +} +else +{ + // Basic protection (against external users only) + if ($user->societe_id > 0) { - $resql = $db->query($sqlprotectagainstexternals); - if ($resql) + if ($sqlprotectagainstexternals) { - $num=$db->num_rows($resql); - $i=0; - while ($i < $num) + $resql = $db->query($sqlprotectagainstexternals); + if ($resql) { - $obj = $db->fetch_object($resql); - if ($user->societe_id != $obj->fk_soc) + $num=$db->num_rows($resql); + $i=0; + while ($i < $num) { - $accessallowed=0; - break; + $obj = $db->fetch_object($resql); + if ($user->societe_id != $obj->fk_soc) + { + $accessallowed=0; + break; + } + $i++; } - $i++; } } } diff --git a/htdocs/ecm/class/ecmfiles.class.php b/htdocs/ecm/class/ecmfiles.class.php index 8e9f5c6557e..a329adfd116 100644 --- a/htdocs/ecm/class/ecmfiles.class.php +++ b/htdocs/ecm/class/ecmfiles.class.php @@ -112,6 +112,7 @@ class EcmFiles //extends CommonObject } if (isset($this->filepath)) { $this->filepath = trim($this->filepath); + $this->filepath = preg_replace('/[\\/]+$/', '', $this->filepath); // Remove last / } if (isset($this->fullpath_orig)) { $this->fullpath_orig = trim($this->fullpath_orig); @@ -164,6 +165,11 @@ class EcmFiles //extends CommonObject $maxposition=$maxposition+1; // Check parameters + if (empty($this->filename) || empty($this->filepath)) + { + $this->errors[] = 'Bad property filename or filepath'; + return -1; + } // Put here code to add control on parameters values // Insert request @@ -349,7 +355,7 @@ class EcmFiles //extends CommonObject $this->errors[] = 'Error ' . $this->db->lasterror(); dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR); - return - 1; + return -1; } } diff --git a/htdocs/ecm/docfile.php b/htdocs/ecm/docfile.php index f6719d08604..339df01b88a 100644 --- a/htdocs/ecm/docfile.php +++ b/htdocs/ecm/docfile.php @@ -64,7 +64,7 @@ $pagenext = $page + 1; if (! $sortorder) $sortorder="ASC"; if (! $sortfield) $sortfield="label"; -$section=GETPOST("section"); +$section=GETPOST("section",'alpha'); if (! $section) { dol_print_error('','Error, section parameter missing'); @@ -101,7 +101,7 @@ $filepathtodocument=$relativetodocument.$file->label; // Try to load object from index $object = new ECMFiles($db); $result=$object->fetch(0, '', $filepathtodocument); -if (! ($result >= 0)) +if ($result < 0) { dol_print_error($db, $object->error, $object->errors); exit; @@ -109,7 +109,6 @@ if (! ($result >= 0)) - /* * Actions */ @@ -124,7 +123,7 @@ if ($cancel) } else { - header("Location: ".DOL_URL_ROOT.'/ecm/docfile.php?urlfile='.$urlfile.'§ion='.$section); + header("Location: ".DOL_URL_ROOT.'/ecm/docfile.php?urlfile='.urlencode($urlfile).'§ion='.urlencode($section)); exit; } } @@ -140,13 +139,18 @@ if ($action == 'update') //$db->begin(); - $olddir=$ecmdir->getRelativePath(0); + $olddir=$ecmdir->getRelativePath(0); // Relative to ecm + $olddirrelativetodocument = 'ecm/'.$olddir; // Relative to document + $newdirrelativetodocument = 'ecm/'.$olddir; $olddir=$conf->ecm->dir_output.'/'.$olddir; $newdir=$olddir; $oldfile=$olddir.$oldlabel; $newfile=$newdir.$newlabel; + // Now we update index of file + $db->begin(); + //print $oldfile.' - '.$newfile; if ($newlabel != $oldlabel) { @@ -157,29 +161,52 @@ if ($action == 'update') setEventMessages($langs->trans('ErrorFailToRenameFile',$oldfile,$newfile), null, 'errors'); $error++; } - } - // Now we update index of file - $db->begin(); + // Reload object after the move + $result=$object->fetch(0, '', $newdirrelativetodocument.$newlabel); + if ($result < 0) + { + dol_print_error($db, $object->error, $object->errors); + exit; + } + } if (! $error) { - if (is_object($object)) + if ($shareenabled) { - if ($shareenabled) - { - require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; - $object->share = getRandomPassword(true); - } - else - { - $object->share = ''; - } + require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; + $object->share = getRandomPassword(true); + } + else + { + $object->share = ''; + } + + if ($object->id > 0) + { + // Call update to set the share key $result = $object->update($user); if ($result < 0) { - $error++; - setEventMessages($object->error, $object->errors, 'errors'); + setEventMessages($object->error, $object->errors, 'warnings'); + } + } + else + { + // Call create to insert record + $object->entity = $conf->entity; + $object->filepath = preg_replace('/[\\/]+$/', '', $newdirrelativetodocument); + $object->filename = $newlabel; + $object->label = md5_file(dol_osencode($newfile)); // hash of file content + $object->fullpath_orig = ''; + $object->gen_or_uploaded = 'unknown'; + $object->description = ''; // indexed content + $object->keyword = ''; // keyword content + $result = $object->create($user); + if ($result < 0) + { + setEventMessages($object->error, $object->errors, 'warnings'); } } } @@ -187,7 +214,10 @@ if ($action == 'update') if (!$error) { $db->commit(); + $urlfile=$newlabel; + header("Location: ".DOL_URL_ROOT.'/ecm/docfile.php?urlfile='.urlencode($urlfile).'§ion='.urlencode($section)); + exit; } else { @@ -297,6 +327,7 @@ $urlwithouturlroot=preg_replace('/'.preg_quote(DOL_URL_ROOT,'/').'$/i','',trim($ $urlwithroot=$urlwithouturlroot.DOL_URL_ROOT; // This is to use external domain name found into config file //$urlwithroot=DOL_MAIN_URL_ROOT; // This is to use same domain name than current +// Link for internal download print '