changed token-size to 32 char (more then plenty), only use tokens containing no special url chars (/#), and do not copy files to tmp-dir in vfs, if identical files already there to use

This commit is contained in:
Ralf Becker 2014-12-05 11:27:22 +00:00
parent 65a9f8e584
commit 6955afccc8
2 changed files with 73 additions and 6 deletions

View File

@ -24,8 +24,11 @@ class egw_sharing
{
/**
* Length of base64 encoded token (real length is only 3/4 of it)
*
* Dropbox uses just 15 chars (letters/numbers 5-6 bit), php sessions use 32 chars (hex = 4bits),
* so 32 chars of base64 = 6bits should be plenty.
*/
const TOKEN_LENGTH = 64;
const TOKEN_LENGTH = 32;
/**
* Name of table used for storing tokens
@ -237,9 +240,12 @@ class egw_sharing
public static function token()
{
// generate random token (using oppenssl if available otherwise mt_rand based auth::randomstring)
$token = function_exists('openssl_random_pseudo_bytes') ?
base64_encode(openssl_random_pseudo_bytes(3*self::TOKEN_LENGTH/4)) :
auth::randomstring(self::TOKEN_LENGTH);
do {
$token = function_exists('openssl_random_pseudo_bytes') ?
base64_encode(openssl_random_pseudo_bytes(3*self::TOKEN_LENGTH/4)) :
auth::randomstring(self::TOKEN_LENGTH);
// base64 can contain chars not allowed in our vfs-urls eg. / or #
} while ($token != egw_vfs::encodePathComponent($token));
return $token;
}
@ -276,7 +282,7 @@ class egw_sharing
$path = 'vfs://default'.($path[0] == '/' ? '' : '/').$path;
}
// check if file exists and is readable
if (!file_exists($path) || is_readable($path))
if (!file_exists($path) || !is_readable($path))
{
throw new egw_exception_not_found("'$path' NOT found!");
}
@ -323,7 +329,9 @@ class egw_sharing
$tmp_file = egw_vfs::concat($user_tmp, ($n?$n.'.':'').egw_vfs::basename($name));
}
while(!(is_dir($path) && egw_vfs::mkdir($tmp_file) ||
!is_dir($path) && ($fp = egw_vfs::fopen($tmp_file, 'x'))) && $n++ < 100);
!is_dir($path) && (!egw_vfs::file_exists($tmp_file) && ($fp = egw_vfs::fopen($tmp_file, 'x')) ||
// do not copy identical files again to users tmp dir, just re-use them
egw_vfs::file_exists($tmp_file) && egw_vfs::compare(egw_vfs::PREFIX.$tmp_file, $path))) && $n++ < 100);
if ($n >= 100)
{
@ -340,6 +348,13 @@ class egw_sharing
$path2tmp[$path] = $tmp_file;
$path = $tmp_file;
// if not already installed, install periodic cleanup of tmp files
$async = new asyncservice();
if (!$async->read('egw_sharing-tmp-cleanup'))
{
$async->set_timer(array('day' => 28),'egw_sharing-tmp_cleanup','egw_sharing::tmp_cleanup',null);
}
}
$i = 0;
@ -366,6 +381,28 @@ class egw_sharing
return $share;
}
/**
* Periodic (monthly) cleanup of temp. sharing files
*/
public static function tmp_cleanup()
{
try {
egw_vfs::$is_root = true;
/* not yet ready
egw_vfs::find('/home', array(
'path_preg' => '|^/home/[^/]+/.tmp',
'maxdepth' => 3,
), function($path, $stat)
{
error_log(__METHOD__."() path=$path");
});*/
}
catch (Exception $e) {
unset($e);
}
egw_vfs::$is_root = false;
}
/**
* Generate link from share or share-token
*

View File

@ -2005,6 +2005,36 @@ class egw_vfs extends vfs_stream_wrapper
if (self::LOG_LEVEL > 1 || !$ret && self::LOG_LEVEL) error_log(__METHOD__."($tmp_name, $target, ".array2string($props).") returning ".array2string($ret));
return $ret;
}
/**
* Compare two files from vfs or local file-system for identical content
*
* VFS files must use URL, to be able to distinguish them eg. from temp. files!
*
* @param string $file1 vfs-url or local path, eg. /tmp/some-file.txt or vfs://default/home/user/some-file.txt
* @param string $file2 -- " --
* @return boolean true: if files are identical, false: if not or file not found
*/
public static function compare($file1, $file2)
{
if (filesize($file1) != filesize($file2) ||
!($fp1 = fopen($file1, 'r')) || !($fp2 = fopen($file2, 'r')))
{
//error_log(__METHOD__."($file1, $file2) returning FALSE (different size)");
return false;
}
while (($read1 = fread($fp1, 8192)) !== false &&
($read2 = fread($fp2, 8192)) !== false &&
$read1 === $read2 && !feof($fp1) && !feof($fp2))
{
// just loop until we find a difference
}
fclose($fp1);
fclose($fp2);
//error_log(__METHOD__."($file1, $file2) returning ".array2string($read1 === $read2)." (content differs)");
return $read1 === $read2;
}
}
egw_vfs::init_static();