diff options
Diffstat (limited to 'Zotlabs/Storage')
-rw-r--r-- | Zotlabs/Storage/BasicAuth.php | 11 | ||||
-rw-r--r-- | Zotlabs/Storage/Browser.php | 73 | ||||
-rw-r--r-- | Zotlabs/Storage/Directory.php | 95 | ||||
-rw-r--r-- | Zotlabs/Storage/File.php | 45 |
4 files changed, 179 insertions, 45 deletions
diff --git a/Zotlabs/Storage/BasicAuth.php b/Zotlabs/Storage/BasicAuth.php index 0ff9fad13..d8af03703 100644 --- a/Zotlabs/Storage/BasicAuth.php +++ b/Zotlabs/Storage/BasicAuth.php @@ -187,14 +187,11 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic { } protected function check_module_access($channel_id) { - if($channel_id && \App::$module === 'cdav') { - $x = get_pconfig($channel_id,'cdav','enabled'); - if(! $x) { - $this->module_disabled = true; - return false; - } + if($channel_id && in_array(\App::$module,[ 'dav', 'cdav', 'snap'] )) { + return true; } - return true; + $this->module_disabled = true; + return false; } /** diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php index a30eedba5..c21b68971 100644 --- a/Zotlabs/Storage/Browser.php +++ b/Zotlabs/Storage/Browser.php @@ -12,11 +12,12 @@ use Sabre\DAV; * * @extends \\Sabre\\DAV\\Browser\\Plugin * - * @link http://github.com/friendica/red + * @link http://github.com/redmatrix/hubzilla * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT) */ class Browser extends DAV\Browser\Plugin { + public $build_page = false; /** * @see set_writeable() * @see \\Sabre\\DAV\\Auth\\Backend\\BackendInterface @@ -84,7 +85,7 @@ class Browser extends DAV\Browser\Plugin { require_once('include/conversation.php'); require_once('include/text.php'); if ($this->auth->owner_nick) { - $html = profile_tabs(get_app(), (($is_owner) ? true : false), $this->auth->owner_nick); + $html = ''; } $files = $this->server->getPropertiesForPath($path, array( @@ -172,6 +173,7 @@ class Browser extends DAV\Browser\Plugin { $displayName = $this->escapeHTML($displayName); $type = $this->escapeHTML($type); + $icon = ''; if ($this->enableAssets) { @@ -195,12 +197,53 @@ class Browser extends DAV\Browser\Plugin { } } + + // generate preview icons for tile view. + // Currently we only handle images, but this could potentially be extended with plugins + // to provide document and video thumbnails. SVG, PDF and office documents have some + // security concerns and should only be allowed on single-user sites with tightly controlled + // upload access. system.thumbnail_security should be set to 1 if you want to include these + // types + + $photo_icon = ''; + $preview_style = intval(get_config('system','thumbnail_security',0)); + + $r = q("select content from attach where hash = '%s' and uid = %d limit 1", + dbesc($attachHash), + intval($owner) + ); + + if($r && file_exists(dbunescbin($r[0]['content']) . '.thumb')) { + $photo_icon = 'data:image/jpeg;base64,' . base64_encode(file_get_contents(dbunescbin($r[0]['content']) . '.thumb')); +// logger('found thumb: ' . $photo_icon); + } + + if(strpos($type,'image/') === 0 && $attachHash) { + $r = q("select resource_id, imgscale from photo where resource_id = '%s' and imgscale in ( %d, %d ) order by imgscale asc limit 1", + dbesc($attachHash), + intval(PHOTO_RES_320), + intval(PHOTO_RES_PROFILE_80) + ); + if($r) { + $photo_icon = 'photo/' . $r[0]['resource_id'] . '-' . $r[0]['imgscale']; + } + if($type === 'image/svg+xml' && $preview_style > 0) { + $photo_icon = $fullPath; + } + } + + $g = [ 'resource_id' => $attachHash, 'thumbnail' => $photo_icon, 'security' => $preview_style ]; + call_hooks('file_thumbnail', $g); + $photo_icon = $g['thumbnail']; + + $attachIcon = ""; // "<a href=\"attach/".$attachHash."\" title=\"".$displayName."\"><i class=\"fa fa-arrow-circle-o-down\"></i></a>"; // put the array for this file together $ft['attachId'] = $this->findAttachIdByHash($attachHash); $ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->getCurrentUser(); $ft['icon'] = $icon; + $ft['photo_icon'] = $photo_icon; $ft['attachIcon'] = (($size) ? $attachIcon : ''); // @todo Should this be an item value, not a global one? $ft['is_owner'] = $is_owner; @@ -215,11 +258,13 @@ class Browser extends DAV\Browser\Plugin { $f[] = $ft; } + $output = ''; if ($this->enablePost) { $this->server->emit('onHTMLActionsPanel', array($parent, &$output, $path)); } + $html .= replace_macros(get_markup_template('cloud.tpl'), array( '$header' => t('Files') . ": " . $this->escapeHTML($path) . "/", '$total' => t('Total'), @@ -229,6 +274,8 @@ class Browser extends DAV\Browser\Plugin { '$upload' => t('Upload'), '$is_owner' => $is_owner, '$parentpath' => $parentpath, + '$cpath' => bin2hex(\App::$query_string), + '$tiles' => intval($_SESSION['cloud_tiles']), '$entries' => $f, '$name' => t('Name'), '$type' => t('Type'), @@ -240,9 +287,13 @@ class Browser extends DAV\Browser\Plugin { '$nick' => $this->auth->getCurrentUser() )); - $a = get_app(); + + $a = false; + + nav_set_selected('Files'); + \App::$page['content'] = $html; - load_pdl($a); + load_pdl(); $current_theme = \Zotlabs\Render\Theme::current(); @@ -255,7 +306,7 @@ class Browser extends DAV\Browser\Plugin { } } $this->server->httpResponse->setHeader('Content-Security-Policy', "script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'"); - construct_page($a); + $this->build_page = true; } /** @@ -314,7 +365,14 @@ class Browser extends DAV\Browser\Plugin { $quota['desc'] = $quotaDesc; $quota['warning'] = ((($limit) && ((round($used / $limit, 1) * 100) >= 90)) ? t('WARNING:') : ''); // 10485760 bytes = 100MB - $path = trim(str_replace('cloud/' . $this->auth->owner_nick, '', $path), '/'); + // strip 'cloud/nickname', but only at the beginning of the path + + $special = 'cloud/' . $this->auth->owner_nick; + $count = strlen($special); + + if(strpos($path,$special) === 0) + $path = trim(substr($path,$count),'/'); + $output .= replace_macros(get_markup_template('cloud_actionspanel.tpl'), array( '$folder_header' => t('Create new folder'), @@ -332,7 +390,8 @@ class Browser extends DAV\Browser\Plugin { '$return_url' => \App::$cmd, '$path' => $path, '$folder' => find_folder_hash_by_path($this->auth->owner_id, $path), - '$dragdroptext' => t('Drop files here to immediately upload') + '$dragdroptext' => t('Drop files here to immediately upload'), + '$notify' => ['notify', t('Show in your contacts shared folder'), 0, '', [t('No'), t('Yes')]] )); } diff --git a/Zotlabs/Storage/Directory.php b/Zotlabs/Storage/Directory.php index 5d078b04e..63ff4341c 100644 --- a/Zotlabs/Storage/Directory.php +++ b/Zotlabs/Storage/Directory.php @@ -16,7 +16,7 @@ use Sabre\DAV; * @link http://github.com/friendica/red * @license http://opensource.org/licenses/mit-license.php The MIT License (MIT) */ -class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { +class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMoveTarget { /** * @brief The path inside /cloud @@ -49,7 +49,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * @param BasicAuth &$auth_plugin */ public function __construct($ext_path, &$auth_plugin) { -// $ext_path = urldecode($ext_path); + // $ext_path = urldecode($ext_path); logger('directory ' . $ext_path, LOGGER_DATA); $this->ext_path = $ext_path; // remove "/cloud" from the beginning of the path @@ -167,6 +167,14 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { intval($this->auth->owner_id) ); + $x = attach_syspaths($this->auth->owner_id,$this->folder_hash); + + $y = q("update attach set display_path = '%s where hash = '%s' and uid = %d", + dbesc($x['path']), + dbesc($this->folder_hash), + intval($this->auth->owner_id) + ); + $ch = channelx_by_n($this->auth->owner_id); if ($ch) { $sync = attach_export_data($ch, $this->folder_hash); @@ -260,14 +268,18 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { dbesc($f), dbesc(datetime_convert()), dbesc(datetime_convert()), - '', //TODO: use os_path - '', //TODO: use display_path + '', + '', dbesc($allow_cid), dbesc($allow_gid), dbesc($deny_cid), dbesc($deny_gid) ); + // fetch the actual storage paths + + $xpath = attach_syspaths($this->auth->owner_id, $hash); + // returns the number of bytes that were written to the file, or FALSE on failure $size = file_put_contents($f, $data); // delete attach entry if file_put_contents() failed @@ -281,15 +293,28 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { $edited = datetime_convert(); $is_photo = 0; - $x = @getimagesize($f); - logger('getimagesize: ' . print_r($x,true), LOGGER_DATA); - if (($x) && ($x[2] === IMAGETYPE_GIF || $x[2] === IMAGETYPE_JPEG || $x[2] === IMAGETYPE_PNG)) { + $gis = @getimagesize($f); + logger('getimagesize: ' . print_r($gis,true), LOGGER_DATA); + if (($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) { $is_photo = 1; } + // If we know it's a photo, over-ride the type in case the source system could not determine what it was + + if($is_photo) { + q("update attach set filetype = '%s' where hash = '%s' and uid = %d", + dbesc($gis['mime']), + dbesc($hash), + intval($c[0]['channel_id']) + ); + } + + // updates entry with filesize and timestamp - $d = q("UPDATE attach SET filesize = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d", + $d = q("UPDATE attach SET filesize = '%s', os_path = '%s', display_path = '%s', is_photo = %d, edited = '%s' WHERE hash = '%s' AND uid = %d", dbesc($size), + dbesc($xpath['os_path']), + dbesc($xpath['display_path']), intval($is_photo), dbesc($edited), dbesc($hash), @@ -312,31 +337,33 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { // check against service class quota $limit = engr_units_to_bytes(service_class_fetch($c[0]['channel_id'], 'attach_upload_limit')); if ($limit !== false) { - $x = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d ", + $z = q("SELECT SUM(filesize) AS total FROM attach WHERE aid = %d ", intval($c[0]['channel_account_id']) ); - if (($x) && ($x[0]['total'] + $size > $limit)) { - logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $x[0]['total'] . ' limit is ' . userReadableSize($limit)); + if (($z) && ($z[0]['total'] + $size > $limit)) { + logger('service class limit exceeded for ' . $c[0]['channel_name'] . ' total usage is ' . $z[0]['total'] . ' limit is ' . userReadableSize($limit)); attach_delete($c[0]['channel_id'], $hash); return; } } - if ($is_photo) { + if($is_photo) { $album = ''; if ($this->folder_hash) { - $f1 = q("select filename from attach WHERE hash = '%s' AND uid = %d", + $f1 = q("select filename, display_path from attach WHERE hash = '%s' AND uid = %d", dbesc($this->folder_hash), intval($c[0]['channel_id']) ); if ($f1) - $album = $f1[0]['filename']; + $album = (($f1[0]['display_path']) ? $f1[0]['display_path'] : $f1[0]['filename']); } require_once('include/photos.php'); - $args = array( 'resource_id' => $hash, 'album' => $album, 'os_path' => $f, 'filename' => $name, 'getimagesize' => $x, 'directory' => $direct); + $args = array( 'resource_id' => $hash, 'album' => $album, 'os_syspath' => $f, 'os_path' => $xpath['os_path'], 'display_path' => $xpath['path'], 'filename' => $name, 'getimagesize' => $gis, 'directory' => $direct); $p = photo_upload($c[0], \App::get_observer(), $args); } + + \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $this->folder_hash ]); $sync = attach_export_data($c[0], $hash); @@ -430,6 +457,22 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { return false; } + + public function moveInto($targetName,$sourcePath, DAV\INode $sourceNode) { + + if(! $this->auth->owner_id) { + return false; + } + + if(! ($sourceNode->data && $sourceNode->data->hash)) { + return false; + } + + return attach_move($this->auth->owner_id, $sourceNode->data->hash, $this->folder_hash); + + } + + /** * @todo add description of what this function does. * @@ -646,20 +689,24 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { logger("Path mismatch: $path !== /$file"); return NULL; } - if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { - $prefix = 'DISTINCT ON (filename)'; - $suffix = 'ORDER BY filename'; - } - else { - $prefix = ''; - $suffix = 'GROUP BY filename'; - } + + $prefix = ''; + $suffix = ''; + $r = q("select $prefix id, uid, hash, filename, filetype, filesize, revision, folder, flags, is_dir, created, edited from attach where folder = '%s' and uid = %d $perms $suffix", dbesc($folder), intval($channel_id) ); foreach ($r as $rr) { + + // @FIXME I don't think we use revisions currently in attach structures. + // In case we see any in the wild provide a unique filename. This + // name may or may not be accessible + + if($rr['revision']) + $rr['filename'] .= '-' . $rr['revision']; + //logger('filename: ' . $rr['filename'], LOGGER_DEBUG); if (intval($rr['is_dir'])) { $ret[] = new Directory($path . '/' . $rr['filename'], $auth); @@ -687,7 +734,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota { $ret = array(); $r = q("SELECT channel_id, channel_address FROM channel WHERE channel_removed = 0 - AND channel_system = 0 AND NOT (channel_pageflags & %d)>0", + AND channel_system = 0 AND (channel_pageflags & %d) = 0", intval(PAGE_HIDDEN) ); diff --git a/Zotlabs/Storage/File.php b/Zotlabs/Storage/File.php index d2bca3964..53d5d3476 100644 --- a/Zotlabs/Storage/File.php +++ b/Zotlabs/Storage/File.php @@ -85,13 +85,23 @@ class File extends DAV\Node implements DAV\IFile { intval($this->data['id']) ); + $x = attach_syspaths($this->auth->owner_id,$this->data['hash']); + + $y = q("update attach set display_path = '%s where hash = '%s' and uid = %d", + dbesc($x['path']), + dbesc($this->data['hash']), + intval($this->auth->owner_id) + ); + if($this->data->is_photo) { - $r = q("update photo set filename = '%s' where resource_id = '%s' and uid = %d", + $r = q("update photo set filename = '%s', display_path = '%s' where resource_id = '%s' and uid = %d", dbesc($newName), + dbesc($x['path']), dbesc($this->data['hash']), intval($this->auth->owner_id) ); } + $ch = channelx_by_n($this->auth->owner_id); if($ch) { $sync = attach_export_data($ch,$this->data['hash']); @@ -117,12 +127,19 @@ class File extends DAV\Node implements DAV\IFile { $is_photo = false; $album = ''; + $os_path = ''; - $r = q("SELECT flags, folder, os_storage, filename, is_photo FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", + $r = q("SELECT flags, folder, os_storage, os_path, display_path, filename, is_photo FROM attach WHERE hash = '%s' AND uid = %d LIMIT 1", dbesc($this->data['hash']), intval($c[0]['channel_id']) ); if ($r) { + + $os_path = $r[0]['os_path']; + $display_path = $r[0]['display_path']; + $filename = $r[0]['filename']; + + if (intval($r[0]['os_storage'])) { $d = q("select folder, content from attach where hash = '%s' and uid = %d limit 1", dbesc($this->data['hash']), @@ -140,7 +157,7 @@ class File extends DAV\Node implements DAV\IFile { } } $fname = dbunescbin($d[0]['content']); - if(strpos($fname,'store') === false) + if(strpos($fname,'store/') === false) $f = 'store/' . $this->auth->owner_nick . '/' . $fname ; else $f = $fname; @@ -155,6 +172,17 @@ class File extends DAV\Node implements DAV\IFile { if(($gis) && ($gis[2] === IMAGETYPE_GIF || $gis[2] === IMAGETYPE_JPEG || $gis[2] === IMAGETYPE_PNG)) { $is_photo = 1; } + + // If we know it's a photo, over-ride the type in case the source system could not determine what it was + + if($is_photo) { + q("update attach set filetype = '%s' where hash = '%s' and uid = %d", + dbesc($gis['mime']), + dbesc($this->data['hash']), + intval($this->data['uid']) + ); + } + } else { // this shouldn't happen any more @@ -186,7 +214,7 @@ class File extends DAV\Node implements DAV\IFile { if($is_photo) { require_once('include/photos.php'); - $args = array( 'resource_id' => $this->data['hash'], 'album' => $album, 'os_path' => $f, 'filename' => $r[0]['filename'], 'getimagesize' => $gis, 'directory' => $direct ); + $args = array( 'resource_id' => $this->data['hash'], 'album' => $album, 'os_syspath' => $f, 'os_path' => $os_path, 'display_path' => $display_path, 'filename' => $filename, 'getimagesize' => $gis, 'directory' => $direct ); $p = photo_upload($c[0],\App::get_observer(),$args); } @@ -220,6 +248,9 @@ class File extends DAV\Node implements DAV\IFile { } } + \Zotlabs\Daemon\Master::Summon([ 'Thumbnail' , $this->data['hash'] ]); + + $sync = attach_export_data($c[0],$this->data['hash']); if($sync) @@ -244,7 +275,7 @@ class File extends DAV\Node implements DAV\IFile { // @todo this should be a global definition $unsafe_types = array('text/html', 'text/css', 'application/javascript'); - if (in_array($r[0]['filetype'], $unsafe_types)) { + if (in_array($r[0]['filetype'], $unsafe_types) && (! channel_codeallowed($this->data['uid']))) { header('Content-disposition: attachment; filename="' . $r[0]['filename'] . '"'); header('Content-type: text/plain'); } @@ -255,7 +286,7 @@ class File extends DAV\Node implements DAV\IFile { $f = 'store/' . $this->auth->owner_nick . '/' . (($this->os_path) ? $this->os_path . '/' : '') . $x; else $f = $x; - return fopen($f, 'rb'); + return @fopen($f, 'rb'); } return dbunescbin($r[0]['content']); } @@ -290,7 +321,7 @@ class File extends DAV\Node implements DAV\IFile { public function getContentType() { // @todo this should be a global definition. $unsafe_types = array('text/html', 'text/css', 'application/javascript'); - if (in_array($this->data['filetype'], $unsafe_types)) { + if (in_array($this->data['filetype'], $unsafe_types) && (! channel_codeallowed($this->data['uid']))) { return 'text/plain'; } return $this->data['filetype']; |