Exemplo n.º 1
0
function attach_init(&$a)
{
    if (argc() < 2) {
        notice(t('Item not available.') . EOL);
        return;
    }
    $r = attach_by_hash(argv(1), argc() > 2 ? intval(argv(2)) : 0);
    if (!$r['success']) {
        notice($r['message'] . EOL);
        return;
    }
    $c = q("select channel_address from channel where channel_id = %d limit 1", intval($r['data']['uid']));
    if (!$c) {
        return;
    }
    $unsafe_types = array('text/html', 'text/css', 'application/javascript');
    if (in_array($r['data']['filetype'], $unsafe_types)) {
        header('Content-type: text/plain');
    } else {
        header('Content-type: ' . $r['data']['filetype']);
    }
    header('Content-disposition: attachment; filename="' . $r['data']['filename'] . '"');
    if ($r['data']['flags'] & ATTACH_FLAG_OS) {
        $istream = fopen('store/' . $c[0]['channel_address'] . '/' . $r['data']['data'], 'rb');
        $ostream = fopen('php://output', 'wb');
        if ($istream && $ostream) {
            pipe_streams($istream, $ostream);
            fclose($istream);
            fclose($ostream);
        }
    } else {
        echo $r['data']['data'];
    }
    killme();
}
Exemplo n.º 2
0
 function post()
 {
     $hash = $_POST['hash'];
     $time = $_POST['time'];
     $sig = $_POST['signature'];
     $resource = $_POST['resource'];
     $revision = intval($_POST['revision']);
     if (!$hash) {
         killme();
     }
     $channel = channelx_by_hash($hash);
     if (!$channel || !$time || !$sig) {
         killme();
     }
     $slop = intval(get_pconfig($channel['channel_id'], 'system', 'getfile_time_slop'));
     if ($slop < 1) {
         $slop = 3;
     }
     $d1 = datetime_convert('UTC', 'UTC', "now + {$slop} minutes");
     $d2 = datetime_convert('UTC', 'UTC', "now - {$slop} minutes");
     if ($time > $d1 || $time < $d2) {
         logger('time outside allowable range');
         killme();
     }
     if (!rsa_verify($hash . '.' . $time, base64url_decode($sig), $channel['channel_pubkey'])) {
         logger('verify failed.');
         killme();
     }
     $r = attach_by_hash($resource, $revision);
     if (!$r['success']) {
         notice($r['message'] . EOL);
         return;
     }
     $unsafe_types = array('text/html', 'text/css', 'application/javascript');
     if (in_array($r['data']['filetype'], $unsafe_types)) {
         header('Content-type: text/plain');
     } else {
         header('Content-type: ' . $r['data']['filetype']);
     }
     header('Content-disposition: attachment; filename="' . $r['data']['filename'] . '"');
     if (intval($r['data']['os_storage'])) {
         $fname = dbunescbin($r['data']['data']);
         if (strpos($fname, 'store') !== false) {
             $istream = fopen($fname, 'rb');
         } else {
             $istream = fopen('store/' . $channel['channel_address'] . '/' . $fname, 'rb');
         }
         $ostream = fopen('php://output', 'wb');
         if ($istream && $ostream) {
             pipe_streams($istream, $ostream);
             fclose($istream);
             fclose($ostream);
         }
     } else {
         echo dbunescbin($r['data']['data']);
     }
     killme();
 }
Exemplo n.º 3
0
 function init()
 {
     $prvcachecontrol = false;
     $streaming = null;
     $channel = null;
     switch (argc()) {
         case 4:
             $person = argv(3);
             $res = argv(2);
             $type = argv(1);
             break;
         case 2:
             $photo = argv(1);
             break;
         case 1:
         default:
             killme();
             // NOTREACHED
     }
     $observer_xchan = get_observer_hash();
     $default = get_default_profile_photo();
     if (isset($type)) {
         /**
          * Profile photos - Access controls on default profile photos are not honoured since they need to be exchanged with remote sites.
          * 
          */
         if ($type === 'profile') {
             switch ($res) {
                 case 'm':
                     $resolution = 5;
                     $default = get_default_profile_photo(80);
                     break;
                 case 's':
                     $resolution = 6;
                     $default = get_default_profile_photo(48);
                     break;
                 case 'l':
                 default:
                     $resolution = 4;
                     break;
             }
         }
         $uid = $person;
         $d = ['imgscale' => $resolution, 'channel_id' => $uid, 'default' => $default, 'data' => '', 'mimetype' => ''];
         call_hooks('get_profile_photo', $d);
         $resolution = $d['imgscale'];
         $uid = $d['channel_id'];
         $default = $d['default'];
         $data = $d['data'];
         $mimetype = $d['mimetype'];
         if (!$data) {
             $r = q("SELECT * FROM photo WHERE imgscale = %d AND uid = %d AND photo_usage = %d LIMIT 1", intval($resolution), intval($uid), intval(PHOTO_PROFILE));
             if ($r) {
                 $data = dbunescbin($r[0]['content']);
                 $mimetype = $r[0]['mimetype'];
             }
             if (intval($r[0]['os_storage'])) {
                 $data = file_get_contents($data);
             }
         }
         if (!$data) {
             $data = file_get_contents($default);
         }
         if (!$mimetype) {
             $mimetype = 'image/png';
         }
     } else {
         /**
          * Other photos
          */
         /* Check for a cookie to indicate display pixel density, in order to detect high-resolution
         			   displays. This procedure was derived from the "Retina Images" by Jeremey Worboys,
         			   used in accordance with the Creative Commons Attribution 3.0 Unported License.
         			   Project link: https://github.com/Retina-Images/Retina-Images
         			   License link: http://creativecommons.org/licenses/by/3.0/
         			*/
         $cookie_value = false;
         if (isset($_COOKIE['devicePixelRatio'])) {
             $cookie_value = intval($_COOKIE['devicePixelRatio']);
         } else {
             // Force revalidation of cache on next request
             $cache_directive = 'no-cache';
             $status = 'no cookie';
         }
         $resolution = 0;
         if (strpos($photo, '.') !== false) {
             $photo = substr($photo, 0, strpos($photo, '.'));
         }
         if (substr($photo, -2, 1) == '-') {
             $resolution = intval(substr($photo, -1, 1));
             $photo = substr($photo, 0, -2);
             // If viewing on a high-res screen, attempt to serve a higher resolution image:
             if ($resolution == 2 && $cookie_value > 1) {
                 $resolution = 1;
             }
         }
         // If using resolution 1, make sure it exists before proceeding:
         if ($resolution == 1) {
             $r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1", dbesc($photo), intval($resolution));
             if (!$r) {
                 $resolution = 2;
             }
         }
         $r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1", dbesc($photo), intval($resolution));
         if ($r) {
             $allowed = $r[0]['uid'] ? perm_is_allowed($r[0]['uid'], $observer_xchan, 'view_storage') : true;
             $sql_extra = permissions_sql($r[0]['uid']);
             if (!$sql_extra) {
                 $sql_extra = ' and true ';
             }
             // Only check permissions on normal photos. Those photos we don't check includes
             // profile photos, xchan photos (which are also profile photos), 'thing' photos,
             // and cover photos
             $sql_extra = " and (( photo_usage = 0 {$sql_extra} ) or photo_usage != 0 )";
             $channel = channelx_by_n($r[0]['uid']);
             // Now we'll see if we can access the photo
             $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d {$sql_extra} LIMIT 1", dbesc($photo), intval($resolution));
             if ($r && $allowed) {
                 $data = dbunescbin($r[0]['content']);
                 $mimetype = $r[0]['mimetype'];
                 if (intval($r[0]['os_storage'])) {
                     $streaming = $data;
                 }
             } else {
                 // Does the picture exist? It may be a remote person with no credentials,
                 // but who should otherwise be able to view it. Show a default image to let
                 // them know permissions was denied. It may be possible to view the image
                 // through an authenticated profile visit.
                 // There won't be many completely unauthorised people seeing this because
                 // they won't have the photo link, so there's a reasonable chance that the person
                 // might be able to obtain permission to view it.
                 $r = q("SELECT * FROM `photo` WHERE `resource_id` = '%s' AND `imgscale` = %d LIMIT 1", dbesc($photo), intval($resolution));
                 if ($r) {
                     logger('mod_photo: forbidden. ' . \App::$query_string);
                     $observer = \App::get_observer();
                     logger('mod_photo: observer = ' . ($observer ? $observer['xchan_addr'] : '(not authenticated)'));
                     $data = file_get_contents('images/nosign.png');
                     $mimetype = 'image/png';
                     $prvcachecontrol = true;
                 }
             }
         }
     }
     if (!isset($data)) {
         if (isset($resolution)) {
             switch ($resolution) {
                 case 4:
                     $data = file_get_contents(get_default_profile_photo());
                     $mimetype = 'image/png';
                     break;
                 case 5:
                     $data = file_get_contents(get_default_profile_photo(80));
                     $mimetype = 'image/png';
                     break;
                 case 6:
                     $data = file_get_contents(get_default_profile_photo(48));
                     $mimetype = 'image/png';
                     break;
                 default:
                     killme();
                     // NOTREACHED
                     break;
             }
         }
     }
     if (isset($res) && intval($res) && $res < 500) {
         $ph = photo_factory($data, $mimetype);
         if ($ph->is_valid()) {
             $ph->scaleImageSquare($res);
             $data = $ph->imageString();
             $mimetype = $ph->getType();
         }
     }
     // Writing in cachefile
     if (isset($cachefile) && $cachefile != '') {
         file_put_contents($cachefile, $data);
     }
     if (function_exists('header_remove')) {
         header_remove('Pragma');
         header_remove('pragma');
     }
     header("Content-type: " . $mimetype);
     if ($prvcachecontrol) {
         // it is a private photo that they have no permission to view.
         // tell the browser not to cache it, in case they authenticate
         // and subsequently have permission to see it
         header("Cache-Control: no-store, no-cache, must-revalidate");
     } else {
         // The photo cache default is 1 day to provide a privacy trade-off,
         // as somebody reducing photo permissions on a photo that is already
         // "in the wild" won't be able to stop the photo from being viewed
         // for this amount amount of time once it is in the browser cache.
         // The privacy expectations of your site members and their perception
         // of privacy where it affects the entire project may be affected.
         // This has performance considerations but we highly recommend you
         // leave it alone.
         $cache = get_config('system', 'photo_cache_time');
         if (!$cache) {
             $cache = 3600 * 24;
         }
         // 1 day
         header("Expires: " . gmdate("D, d M Y H:i:s", time() + $cache) . " GMT");
         header("Cache-Control: max-age=" . $cache);
     }
     // If it's a file resource, stream it.
     if ($streaming && $channel) {
         if (strpos($streaming, 'store') !== false) {
             $istream = fopen($streaming, 'rb');
         } else {
             $istream = fopen('store/' . $channel['channel_address'] . '/' . $streaming, 'rb');
         }
         $ostream = fopen('php://output', 'wb');
         if ($istream && $ostream) {
             pipe_streams($istream, $ostream);
             fclose($istream);
             fclose($ostream);
         }
     } else {
         echo $data;
     }
     killme();
     // NOTREACHED
 }