diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/Contact.php | 13 | ||||
-rw-r--r-- | include/auth.php | 127 | ||||
-rw-r--r-- | include/cli_startup.php | 6 | ||||
-rw-r--r-- | include/conversation.php | 6 | ||||
-rwxr-xr-x | include/diaspora.php | 73 | ||||
-rw-r--r-- | include/follow.php | 2 | ||||
-rw-r--r-- | include/hubloc.php | 6 | ||||
-rw-r--r-- | include/identity.php | 41 | ||||
-rwxr-xr-x | include/items.php | 10 | ||||
-rw-r--r-- | include/nav.php | 12 | ||||
-rw-r--r-- | include/permissions.php | 5 | ||||
-rw-r--r-- | include/photo/photo_driver.php | 2 | ||||
-rwxr-xr-x | include/plugin.php | 1 | ||||
-rw-r--r-- | include/poller.php | 7 | ||||
-rw-r--r-- | include/reddav.php | 195 | ||||
-rw-r--r-- | include/statistics_fns.php | 73 | ||||
-rw-r--r-- | include/zot.php | 2 |
17 files changed, 442 insertions, 139 deletions
diff --git a/include/Contact.php b/include/Contact.php index 8d50b1e5b..4440369dc 100644 --- a/include/Contact.php +++ b/include/Contact.php @@ -328,6 +328,19 @@ function mark_orphan_hubsxchans() { intval(HUBLOC_OFFLINE) ); +// $realm = get_directory_realm(); +// if($realm == DIRECTORY_REALM) { +// $r = q("select * from site where site_access != 0 and site_register !=0 and ( site_realm = '%s' or site_realm = '') order by rand()", +// dbesc($realm) +// ); +// } +// else { +// $r = q("select * from site where site_access != 0 and site_register !=0 and site_realm = '%s' order by rand()", +// dbesc($realm) +// ); +// } + + $r = q("select hubloc_id, hubloc_hash from hubloc where (hubloc_status & %d) and not (hubloc_flags & %d)", intval(HUBLOC_OFFLINE), intval(HUBLOC_FLAGS_ORPHANCHECK) diff --git a/include/auth.php b/include/auth.php index f8188f443..8f68fc562 100644 --- a/include/auth.php +++ b/include/auth.php @@ -1,11 +1,23 @@ -<?php /** @file */ - +<?php +/** + * @file include/auth.php + * @brief Functions and inline functionality for authentication. + * + * This file provides some functions for authentication handling and inline + * functionality. Look for auth parameters or re-validate an existing session + * also handles logout. + * Also provides a function for OpenID identiy matching. + */ require_once('include/security.php'); +/** + * @brief Resets the current session. + * + * @return void + */ function nuke_session() { - - new_cookie(0); + new_cookie(0); // 0 means delete on browser exit unset($_SESSION['authenticated']); unset($_SESSION['account_id']); @@ -27,21 +39,24 @@ function nuke_session() { } /** - * Verify login credentials - * - * Returns account record on success, null on failure + * @brief Verify login credentials. * + * @param string $email + * The email address to verify. + * @param string $pass + * The provided password to verify. + * @return array|null + * Returns account record on success, null on failure. */ +function account_verify_password($email, $pass) { -function account_verify_password($email,$pass) { - - $email_verify = get_config('system','verify_email'); - $register_policy = get_config('system','register_policy'); + $email_verify = get_config('system', 'verify_email'); + $register_policy = get_config('system', 'register_policy'); // Currently we only verify email address if there is an open registration policy. // This isn't because of any policy - it's because the workflow gets too complicated if // you have to verify the email and then go through the account approval workflow before - // letting them login. + // letting them login. if(($email_verify) && ($register_policy == REGISTER_OPEN) && ($record['account_flags'] & ACCOUNT_UNVERIFIED)) return null; @@ -51,9 +66,10 @@ function account_verify_password($email,$pass) { ); if(! ($r && count($r))) return null; + foreach($r as $record) { if(($record['account_flags'] == ACCOUNT_OK) - && (hash('whirlpool',$record['account_salt'] . $pass) === $record['account_password'])) { + && (hash('whirlpool', $record['account_salt'] . $pass) === $record['account_password'])) { logger('password verified for ' . $email); return $record; } @@ -61,7 +77,6 @@ function account_verify_password($email,$pass) { $error = 'password failed for ' . $email; logger($error); - if($record['account_flags'] & ACCOUNT_UNVERIFIED) logger('Account is unverified. account_flags = ' . $record['account_flags']); if($record['account_flags'] & ACCOUNT_BLOCKED) @@ -88,14 +103,12 @@ function account_verify_password($email,$pass) { * also handles logout */ - -if((isset($_SESSION)) && (x($_SESSION,'authenticated')) && ((! (x($_POST,'auth-params'))) || ($_POST['auth-params'] !== 'login'))) { - +if((isset($_SESSION)) && (x($_SESSION, 'authenticated')) && + ((! (x($_POST, 'auth-params'))) || ($_POST['auth-params'] !== 'login'))) { // process a logout request - if(((x($_POST,'auth-params')) && ($_POST['auth-params'] === 'logout')) || ($a->module === 'logout')) { - + if(((x($_POST, 'auth-params')) && ($_POST['auth-params'] === 'logout')) || ($a->module === 'logout')) { // process logout request $args = array('channel_id' => local_user()); call_hooks('logging_out', $args); @@ -106,16 +119,16 @@ if((isset($_SESSION)) && (x($_SESSION,'authenticated')) && ((! (x($_POST,'auth-p // re-validate a visitor, optionally invoke "su" if permitted to do so - if(x($_SESSION,'visitor_id') && (! x($_SESSION,'uid'))) { + if(x($_SESSION, 'visitor_id') && (! x($_SESSION, 'uid'))) { // if our authenticated guest is allowed to take control of the admin channel, make it so. - $admins = get_config('system','remote_admin'); - if($admins && is_array($admins) && in_array($_SESSION['visitor_id'],$admins)) { + $admins = get_config('system', 'remote_admin'); + if($admins && is_array($admins) && in_array($_SESSION['visitor_id'], $admins)) { $x = q("select * from account where account_email = '%s' and account_email != '' and ( account_flags & %d ) limit 1", - dbesc(get_config('system','admin_email')), + dbesc(get_config('system', 'admin_email')), intval(ACCOUNT_ROLE_ADMIN) ); if($x) { - new_cookie(60*60*24); // one day + new_cookie(60 * 60 * 24); // one day $_SESSION['last_login_date'] = datetime_convert(); unset($_SESSION['visitor_id']); // no longer a visitor authenticate_success($x[0], true, true); @@ -137,20 +150,19 @@ if((isset($_SESSION)) && (x($_SESSION,'authenticated')) && ((! (x($_POST,'auth-p // already logged in user returning - if(x($_SESSION,'uid') || x($_SESSION,'account_id')) { + if(x($_SESSION, 'uid') || x($_SESSION, 'account_id')) { // first check if we're enforcing that sessions can't change IP address - + // @todo what to do with IPv6 addresses if($_SESSION['addr'] && $_SESSION['addr'] != $_SERVER['REMOTE_ADDR']) { logger('SECURITY: Session IP address changed: ' . $_SESSION['addr'] . ' != ' . $_SERVER['REMOTE_ADDR']); - $partial1 = substr($_SESSION['addr'],0,strrpos($_SESSION['addr'],'.')); - $partial2 = substr($_SERVER['REMOTE_ADDR'],0,strrpos($_SERVER['REMOTE_ADDR'],'.')); + $partial1 = substr($_SESSION['addr'], 0, strrpos($_SESSION['addr'], '.')); + $partial2 = substr($_SERVER['REMOTE_ADDR'], 0, strrpos($_SERVER['REMOTE_ADDR'], '.')); - - $paranoia = intval(get_pconfig($_SESSION['uid'],'system','paranoia')); + $paranoia = intval(get_pconfig($_SESSION['uid'], 'system', 'paranoia')); if(! $paranoia) - $paranoia = intval(get_config('system','paranoia')); + $paranoia = intval(get_config('system', 'paranoia')); switch($paranoia) { case 0: @@ -158,8 +170,8 @@ if((isset($_SESSION)) && (x($_SESSION,'authenticated')) && ((! (x($_POST,'auth-p break; case 2: // check 2 octets - $partial1 = substr($partial1,0,strrpos($partial1,'.')); - $partial2 = substr($partial2,0,strrpos($partial2,'.')); + $partial1 = substr($partial1, 0, strrpos($partial1, '.')); + $partial2 = substr($partial2, 0, strrpos($partial2, '.')); if($partial1 == $partial2) break; case 1: @@ -169,12 +181,11 @@ if((isset($_SESSION)) && (x($_SESSION,'authenticated')) && ((! (x($_POST,'auth-p case 3: default: // check any difference at all - logger('Session address changed. Paranoid setting in effect, blocking session. ' + logger('Session address changed. Paranoid setting in effect, blocking session. ' . $_SESSION['addr'] . ' != ' . $_SERVER['REMOTE_ADDR']); nuke_session(); goaway(z_root()); break; - } } @@ -191,17 +202,15 @@ if((isset($_SESSION)) && (x($_SESSION,'authenticated')) && ((! (x($_POST,'auth-p if(strcmp(datetime_convert('UTC','UTC','now - 12 hours'), $_SESSION['last_login_date']) > 0 ) { $_SESSION['last_login_date'] = datetime_convert(); $login_refresh = true; - } - authenticate_success($r[0], false, false, false, $login_refresh); + } + authenticate_success($r[0], false, false, false, $login_refresh); } else { $_SESSION['account_id'] = 0; nuke_session(); goaway(z_root()); } - - } - + } // end logged in user returning } else { @@ -211,10 +220,10 @@ else { // handle a fresh login request - if((x($_POST,'password')) && strlen($_POST['password'])) - $encrypted = hash('whirlpool',trim($_POST['password'])); + if((x($_POST, 'password')) && strlen($_POST['password'])) + $encrypted = hash('whirlpool', trim($_POST['password'])); - if((x($_POST,'auth-params')) && $_POST['auth-params'] === 'login') { + if((x($_POST, 'auth-params')) && $_POST['auth-params'] === 'login') { $record = null; @@ -239,8 +248,7 @@ else { $record = $addon_auth['user_record']; } else { - - $record = get_app()->account = account_verify_password($_POST['username'],$_POST['password']); + $record = get_app()->account = account_verify_password($_POST['username'], $_POST['password']); if(get_app()->account) { $_SESSION['account_id'] = get_app()->account['account_id']; @@ -249,21 +257,20 @@ else { notice( t('Failed authentication') . EOL); } - logger('authenticate: ' . print_r(get_app()->account,true), LOGGER_DEBUG); - + logger('authenticate: ' . print_r(get_app()->account, true), LOGGER_DEBUG); } if((! $record) || (! count($record))) { $error = 'authenticate: failed login attempt: ' . notags(trim($_POST['username'])) . ' from IP ' . $_SERVER['REMOTE_ADDR']; logger($error); // Also log failed logins to a separate auth log to reduce overhead for server side intrusion prevention - $authlog = get_config('system', 'authlog'); - if ($authlog) - @file_put_contents($authlog, datetime_convert() . ':' . session_id() . ' ' . $error . "\n", FILE_APPEND); + $authlog = get_config('system', 'authlog'); + if ($authlog) + @file_put_contents($authlog, datetime_convert() . ':' . session_id() . ' ' . $error . "\n", FILE_APPEND); notice( t('Login failed.') . EOL ); goaway(z_root()); - } + } // If the user specified to remember the authentication, then change the cookie // to expire after one year (the default is when the browser is closed). @@ -293,11 +300,25 @@ else { } +/** + * @brief Returns the channel_id for a given openid_identity. + * + * Queries the values from pconfig configuration for the given openid_identity + * and returns the corresponding channel_id. + * + * @fixme How do we prevent that an OpenID identity is used more than once? + * + * @param string $authid + * The given openid_identity + * @return int|bool + * Return channel_id from pconfig or false. + */ function match_openid($authid) { - $r = q("select * from pconfig where cat = 'system' and k = 'openid' and v = '%s' limit 1", + // Query the uid/channel_id from pconfig for a given value. + $r = q("SELECT uid FROM pconfig WHERE cat = 'system' AND k = 'openid' AND v = '%s' LIMIT 1", dbesc($authid) ); if($r) return $r[0]['uid']; return false; -} +} diff --git a/include/cli_startup.php b/include/cli_startup.php index 6bd4e7520..f90a75cd1 100644 --- a/include/cli_startup.php +++ b/include/cli_startup.php @@ -6,7 +6,7 @@ require_once('boot.php'); function cli_startup() { - global $a, $db; + global $a, $db, $default_timezone; if(is_null($a)) { $a = new App; @@ -14,6 +14,10 @@ function cli_startup() { if(is_null($db)) { @include(".htconfig.php"); + + $a->timezone = ((x($default_timezone)) ? $default_timezone : 'UTC'); + date_default_timezone_set($a->timezone); + require_once('include/dba/dba_driver.php'); $db = dba_factory($db_host, $db_port, $db_user, $db_pass, $db_data); unset($db_host, $db_port, $db_user, $db_pass, $db_data); diff --git a/include/conversation.php b/include/conversation.php index b0a388a68..92ba18d13 100644 --- a/include/conversation.php +++ b/include/conversation.php @@ -1341,8 +1341,10 @@ function prepare_page($item) { // the template will get passed an unobscured title. $body = prepare_body($item,true); - - return replace_macros(get_markup_template('page_display.tpl'),array( + $tpl = get_pconfig($item['uid'],'system','pagetemplate'); + if (! $tpl) + $tpl = 'page_display.tpl'; + return replace_macros(get_markup_template($tpl),array( '$author' => (($naked) ? '' : $item['author']['xchan_name']), '$auth_url' => (($naked) ? '' : zid($item['author']['xchan_url'])), '$date' => (($naked) ? '' : datetime_convert('UTC',date_default_timezone_get(),$item['created'],'Y-m-d H:i')), diff --git a/include/diaspora.php b/include/diaspora.php index f9fd3b4ee..0d4271cee 100755 --- a/include/diaspora.php +++ b/include/diaspora.php @@ -206,10 +206,7 @@ function diaspora_process_outbound($arr) { if(! $contact['xchan_pubkey']) continue; - if(activity_match($target_item['verb'],ACTIVITY_DISLIKE)) { - continue; - } - elseif(($target_item['item_restrict'] & ITEM_DELETED) + if(($target_item['item_restrict'] & ITEM_DELETED) && (($target_item['mid'] === $target_item['parent_mid']) || $arr['followup'])) { // send both top-level retractions and relayable retractions for owner to relay diaspora_send_retraction($target_item,$arr['channel'],$contact); @@ -238,11 +235,7 @@ function diaspora_process_outbound($arr) { $contact = $arr['hub']; - if($target_item['verb'] === ACTIVITY_DISLIKE) { - // unsupported - return; - } - elseif(($target_item['deleted']) + if(($target_item['deleted']) && ($target_item['mid'] === $target_item['parent_mod'])) { // top-level retraction logger('delivery: diaspora retract: ' . $loc); @@ -256,7 +249,6 @@ function diaspora_process_outbound($arr) { return; } elseif($arr['top_level_post']) { - // currently no workable solution for sending walltowall logger('delivery: diaspora status: ' . $loc); diaspora_send_status($target_item,$arr['channel'],$contact,true); return; @@ -910,6 +902,44 @@ function diaspora_post($importer,$xml,$msg) { } + +function get_diaspora_reshare_xml($url,$recurse = 0) { + + $x = z_fetch_url($url); + if(! $x['success']) + $x = z_fetch_url(str_replace('https://','http://',$source_url)); + if(! $x['success']) { + logger('get_diaspora_reshare_xml: unable to fetch source url ' . $source_url); + return; + } + logger('diaspora_reshare: source: ' . $x['body'], LOGGER_DATA); + + $source_xml = parse_xml_string($x['body'],false); + + if(! $source_xml) { + logger('get_diaspora_reshare_xml: unparseable result from ' . $url); + return ''; + } + + if($source_xml->post->status_message) { + return $source_xml; + } + + // see if it's a reshare of a reshare + + if($source_xml->root_diaspora_id && $source_xml->root_guid && $recurse < 15) { + $orig_author = notags(unxmlify($xml->root_diaspora_id)); + $orig_guid = notags(unxmlify($xml->root_guid)); + $source_url = 'https://' . substr($orig_author,strpos($orig_author,'@')+1) . '/p/' . $orig_guid . '.xml'; + $y = get_diaspora_reshare_xml($source_url,$recurse+1); + if($y) + return $y; + } + return false; +} + + + function diaspora_reshare($importer,$xml,$msg) { logger('diaspora_reshare: init: ' . print_r($xml,true), LOGGER_DATA); @@ -948,16 +978,8 @@ function diaspora_reshare($importer,$xml,$msg) { $source_url = 'https://' . substr($orig_author,strpos($orig_author,'@')+1) . '/p/' . $orig_guid . '.xml'; $orig_url = 'https://'.substr($orig_author,strpos($orig_author,'@')+1).'/posts/'.$orig_guid; - $x = z_fetch_url($source_url); - if(! $x['success']) - $x = z_fetch_url(str_replace('https://','http://',$source_url)); - if(! $x['success']) { - logger('diaspora_reshare: unable to fetch source url ' . $source_url); - return; - } - logger('diaspora_reshare: source: ' . $x['body'], LOGGER_DATA); - $source_xml = parse_xml_string($x['body'],false); + $source_xml = get_diaspora_reshare_xml($source_url); if($source_xml->post->status_message) { $body = diaspora2bb($source_xml->post->status_message->raw_message); @@ -1003,9 +1025,9 @@ function diaspora_reshare($importer,$xml,$msg) { . "' profile='" . $orig_author_link . "' avatar='" . $orig_author_photo . "' link='" . $orig_url - . "' posted='" . datetime_convert('UTC','UTC',unxmlify($sourcexml->post->status_message->created_at)) + . "' posted='" . datetime_convert('UTC','UTC',unxmlify($source_xml->post->status_message->created_at)) . "' message_id='" . unxmlify($source_xml->post->status_message->guid) - . "]" . $body . "[/share]"; + . "']" . $body . "[/share]"; $created = unxmlify($xml->created_at); @@ -2401,7 +2423,7 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) { // Diaspora doesn't support threaded comments, but some // versions of Diaspora (i.e. Diaspora-pistos) support // likes on comments - if($item['verb'] === ACTIVITY_LIKE && $item['thr_parent']) { + if(($item['verb'] === ACTIVITY_LIKE || $item['verb'] === ACTIVITY_DISLIKE) && $item['thr_parent']) { $p = q("select mid, parent_mid from item where mid = '%s' limit 1", dbesc($item['thr_parent']) ); @@ -2420,10 +2442,10 @@ function diaspora_send_followup($item,$owner,$contact,$public_batch = false) { else return; - if($item['verb'] === ACTIVITY_LIKE) { + if(($item['verb'] === ACTIVITY_LIKE) && ($parent['mid'] === $parent['parent_mid'])) { $tpl = get_markup_template('diaspora_like.tpl'); $like = true; - $target_type = ( $parent['mid'] === $parent['parent_mid'] ? 'Post' : 'Comment'); + $target_type = 'Post'; $positive = 'true'; if(($item_['item_restrict'] & ITEM_DELETED)) @@ -2604,6 +2626,9 @@ function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { $parentauthorsig = base64_encode(rsa_sign($sender_signed_text,$owner['channel_prvkey'],'sha256')); + if(! $text) + logger('diaspora_send_relay: no text'); + $msg = replace_macros($tpl,array( '$guid' => xmlify($item['mid']), '$parent_guid' => xmlify($parent['mid']), diff --git a/include/follow.php b/include/follow.php index a967386e9..c8bd3c500 100644 --- a/include/follow.php +++ b/include/follow.php @@ -84,7 +84,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false) // Premium channel, set confirm before callback to avoid recursion - if(array_key_exists('connect_url',$j) && (! $confirm)) + if(array_key_exists('connect_url',$j) && ($interactive) && (! $confirm)) goaway(zid($j['connect_url'])); diff --git a/include/hubloc.php b/include/hubloc.php index cdc9de4af..fded434d2 100644 --- a/include/hubloc.php +++ b/include/hubloc.php @@ -105,9 +105,9 @@ function remove_obsolete_hublocs() { dbesc($rr['hubloc_hash']) ); if($x) { -// proc_run('php','include/notifier.php','location',$x[0]['channel_id']); -// if($interval) -// @time_sleep_until(microtime(true) + (float) $interval); + proc_run('php','include/notifier.php','location',$x[0]['channel_id']); + if($interval) + @time_sleep_until(microtime(true) + (float) $interval); } } } diff --git a/include/identity.php b/include/identity.php index bfdd02682..fafb97bbb 100644 --- a/include/identity.php +++ b/include/identity.php @@ -27,10 +27,13 @@ function identity_check_service_class($account_id) { intval(PAGE_REMOVED) ); if(! ($r && count($r))) { + $ret['total_identities'] = 0; $ret['message'] = t('Unable to obtain identity information from database'); return $ret; } + $ret['total_identities'] = intval($r[0]['total']); + if(! service_class_allows($account_id,'total_identities',$r[0]['total'])) { $result['message'] .= upgrade_message(); return $result; @@ -166,10 +169,12 @@ function create_identity($arr) { $ret['message'] = t('No account identifier'); return $ret; } - $ret=identity_check_service_class($arr['account_id']); + $ret = identity_check_service_class($arr['account_id']); if (!$ret['success']) { return $ret; } + // save this for auto_friending + $total_identities = $ret['total_identities']; $nick = mb_strtolower(trim($arr['nickname'])); if(! $nick) { @@ -249,8 +254,8 @@ function create_identity($arr) { $r = q("insert into channel ( channel_account_id, channel_primary, channel_name, channel_address, channel_guid, channel_guid_sig, - channel_hash, channel_prvkey, channel_pubkey, channel_pageflags, channel_expire_days $perms_keys ) - values ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d $perms_vals ) ", + channel_hash, channel_prvkey, channel_pubkey, channel_pageflags, channel_expire_days, channel_timezone $perms_keys ) + values ( %d, %d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s' $perms_vals ) ", intval($arr['account_id']), intval($primary), @@ -262,7 +267,8 @@ function create_identity($arr) { dbesc($key['prvkey']), dbesc($key['pubkey']), intval($pageflags), - intval($expire) + intval($expire), + dbesc($a->timezone) ); @@ -389,6 +395,20 @@ function create_identity($arr) { } } + // auto-follow any of the hub's pre-configured channel choices. + // Only do this if it's the first channel for this account; + // otherwise it could get annoying. Don't make this list too big + // or it will impact registration time. + + $accts = get_config('system','auto_follow'); + if(($accts) && (! $total_identities)) { + if(! is_array($accts)) + $accts = array($accts); + foreach($accts as $acct) { + if(trim($acct)) + new_contact($newuid,trim($acct),$ret['channel'],false); + } + } call_hooks('register_account', $newuid); @@ -518,6 +538,17 @@ function identity_basic_export($channel_id, $items = false) { $ret['photo'] = array('type' => $r[0]['type'], 'data' => base64url_encode($r[0]['data'])); } + + // All other term types will be included in items, if requested. + + $r = q("select * from term where type in (%d,%d) and uid = %d", + intval(TERM_SAVEDSEARCH), + intval(TERM_THING), + intval($channel_id) + ); + if($r) + $ret['term'] = $r; + $r = q("select * from obj where obj_channel = %d", intval($channel_id) ); @@ -1338,7 +1369,7 @@ function get_default_profile_photo($size = 175) { $scheme = get_config('system','default_profile_photo'); if(! $scheme) $scheme = 'rainbow_man'; - return 'images/default_profile_photos/' . $scheme . '/' . $size . '.jpg'; + return 'images/default_profile_photos/' . $scheme . '/' . $size . '.png'; } diff --git a/include/items.php b/include/items.php index 31364de60..c9810bb7c 100755 --- a/include/items.php +++ b/include/items.php @@ -759,6 +759,8 @@ function get_item_elements($x) { $arr = array(); $arr['body'] = (($x['body']) ? htmlspecialchars($x['body'],ENT_COMPAT,'UTF-8',false) : ''); + $key = get_config('system','pubkey'); + $maxlen = get_max_import_size(); if($maxlen && mb_strlen($arr['body']) > $maxlen) { @@ -813,7 +815,7 @@ function get_item_elements($x) { $arr['sig'] = (($x['signature']) ? htmlspecialchars($x['signature'], ENT_COMPAT,'UTF-8',false) : ''); - $arr['diaspora_meta'] = (($x['diaspora_meta']) ? $x['diaspora_meta'] : ''); + $arr['diaspora_meta'] = (($x['diaspora_signature']) ? json_encode(crypto_encapsulate($x['diaspora_signature'],$key)) : ''); $arr['object'] = activity_sanitise($x['object']); $arr['target'] = activity_sanitise($x['target']); @@ -865,7 +867,6 @@ function get_item_elements($x) { // We have to do that here because we need to cleanse the input and prevent bad stuff from getting in, // and we need plaintext to do that. - $key = get_config('system','pubkey'); if(intval($arr['item_private'])) { @@ -891,7 +892,6 @@ function get_item_elements($x) { $arr['resource_type'] = $x['resource_type']; $arr['item_restrict'] = $x['item_restrict']; $arr['item_flags'] = $x['item_flags']; - $arr['diaspora_meta'] = (($x['diaspora_meta']) ? json_encode(crypto_encapsulate($x['diaspora_meta'],$key)) : ''); $arr['attach'] = $x['attach']; } @@ -1078,7 +1078,6 @@ function encode_item($item,$mirror = false) { $x['resource_type'] = $item['resource_type']; $x['item_restrict'] = $item['item_restrict']; $x['item_flags'] = $item['item_flags']; - $x['diaspora_meta'] = crypto_unencapsulate(json_decode($item['diaspora_meta'],true),$key); $x['attach'] = $item['attach']; } @@ -1127,6 +1126,9 @@ function encode_item($item,$mirror = false) { if($item['term']) $x['tags'] = encode_item_terms($item['term']); + if($item['diaspora_meta']) + $x['diaspora_signature'] = crypto_unencapsulate(json_decode($item['diaspora_meta'],true),$key); + logger('encode_item: ' . print_r($x,true), LOGGER_DATA); return $x; diff --git a/include/nav.php b/include/nav.php index 98d1b644e..7c9abce49 100644 --- a/include/nav.php +++ b/include/nav.php @@ -185,7 +185,10 @@ EOT; if(local_user()) { - $nav['network'] = array('network', t('Matrix'), "", t('Your matrix')); + $network_options = get_pconfig(local_user(),'system','network_page_default'); + + $nav['network'] = array('network' . (($network_options) ? '?f=&' . $network_options : ''), + t('Matrix'), "", t('Your matrix')); $nav['network']['mark'] = array('', t('Mark all matrix notifications seen'), '',''); $nav['home'] = array('channel/' . $channel['channel_address'], t('Channel Home'), "", t('Channel home')); @@ -239,6 +242,12 @@ EOT; $x = array('nav' => $nav, 'usermenu' => $userinfo ); call_hooks('nav', $x); +// Not sure the best place to put this on the page. So I'm implementing it but leaving it +// turned off until somebody discovers this and figures out a good location for it. +$powered_by = ''; + +// $powered_by = '<strong>red<img class="smiley" src="' . $a->get_baseurl() . '/images/rm-16.png" alt="r#" />matrix</strong>'; + $tpl = get_markup_template('nav.tpl'); $a->page['nav'] .= replace_macros($tpl, array( @@ -250,6 +259,7 @@ EOT; '$userinfo' => $x['usermenu'], '$localuser' => local_user(), '$sel' => $a->nav_sel, + '$powered_by' => $powered_by, '$pleasewait' => t('Please wait...') )); diff --git a/include/permissions.php b/include/permissions.php index 438b807d0..61ac8aea3 100644 --- a/include/permissions.php +++ b/include/permissions.php @@ -722,6 +722,11 @@ function get_role_perms($role) { } + $x = get_config('system','role_perms'); + // let system settings over-ride any or all + if($x && is_array($x) && array_key_exists($role,$x)) + $ret = array_merge($ret,$x[$role]); + call_hooks('get_role_perms',$ret); return $ret; diff --git a/include/photo/photo_driver.php b/include/photo/photo_driver.php index daf1bfc25..d9777b1c4 100644 --- a/include/photo/photo_driver.php +++ b/include/photo/photo_driver.php @@ -623,7 +623,7 @@ function import_profile_photo($photo,$xchan,$thing = false) { $photo = $a->get_baseurl() . '/' . get_default_profile_photo(); $thumb = $a->get_baseurl() . '/' . get_default_profile_photo(80); $micro = $a->get_baseurl() . '/' . get_default_profile_photo(48); - $type = 'image/jpeg'; + $type = 'image/png'; } return(array($photo,$thumb,$micro,$type,$photo_failure)); diff --git a/include/plugin.php b/include/plugin.php index c2e08a989..4f9ab71da 100755 --- a/include/plugin.php +++ b/include/plugin.php @@ -552,6 +552,7 @@ function theme_include($file, $root = '') { $paths = array( "{$root}view/theme/$theme/$ext/$file", "{$root}view/theme/$parent/$ext/$file", + "{$root}view/site/$ext/$file", "{$root}view/$ext/$file", ); diff --git a/include/poller.php b/include/poller.php index f689059b9..2febaeb32 100644 --- a/include/poller.php +++ b/include/poller.php @@ -149,6 +149,13 @@ function poller_run($argv, $argc){ update_birthdays(); + //update statistics in config + require_once('include/statistics_fns.php'); + update_channels_total_stat(); + update_channels_active_halfyear_stat(); + update_channels_active_monthly_stat(); + update_local_posts_stat(); + // expire any read notifications over a month old q("delete from notify where seen = 1 and date < UTC_TIMESTAMP() - INTERVAL 30 DAY"); diff --git a/include/reddav.php b/include/reddav.php index c4ef5bd08..3de24661e 100644 --- a/include/reddav.php +++ b/include/reddav.php @@ -9,6 +9,8 @@ * You find the original SabreDAV classes under @ref vendor/sabre/dav/. * We need to use SabreDAV 1.8.x for PHP5.3 compatibility. SabreDAV >= 2.0 * requires PHP >= 5.4. + * + * @todo split up the classes into own files. */ use Sabre\DAV; @@ -25,6 +27,8 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { /** * @brief The path inside /cloud + * + * @var string */ private $red_path; private $folder_hash; @@ -32,6 +36,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { * @brief The full path as seen in the browser. * /cloud + $red_path * @todo I think this is not used anywhere, we always strip '/cloud' and only use it in debug + * @var string */ private $ext_path; private $root_dir = ''; @@ -39,6 +44,8 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { /** * @brief The real path on the filesystem. * The actual path in store/ with the hashed names. + * + * @var string */ private $os_path = ''; @@ -107,7 +114,7 @@ class RedDirectory extends DAV\Node implements DAV\ICollection, DAV\IQuota { if (get_config('system', 'block_public') && (! $this->auth->channel_id) && (! $this->auth->observer)) { throw new DAV\Exception\Forbidden('Permission denied.'); } - + if (($this->auth->owner_id) && (! perm_is_allowed($this->auth->owner_id, $this->auth->observer, 'view_storage'))) { throw new DAV\Exception\Forbidden('Permission denied.'); } @@ -971,78 +978,111 @@ function RedFileData($file, &$auth, $test = false) { /** - * RedBasicAuth class. + * @brief Authentication backend class for RedDAV. + * + * This class also contains some data which is not necessary for authentication + * like timezone settings. * */ class RedBasicAuth extends DAV\Auth\Backend\AbstractBasic { - // @fixme mod/cloud.php:61 - public $channel_name = ''; - // @fixme mod/cloud.php:62 + /** + * @brief This variable holds the currently logged-in channel_address. + * + * It is used for building path in filestorage/. + * + * @var string|null + */ + protected $channel_name = null; + /** + * channel_id of the current channel of the logged-in account. + * + * @var int + */ public $channel_id = 0; - // @fixme mod/cloud.php:63 + /** + * channel_hash of the current channel of the logged-in account. + * + * @var string + */ public $channel_hash = ''; - // @fixme mod/cloud.php:68 + /** + * Set in mod/cloud.php to observer_hash. + * + * @var string + */ public $observer = ''; - // @fixme include/reddav.php:51 + /** + * + * @see RedBrowser::set_writeable() + * @var DAV\Browser\Plugin + */ public $browser; - // @fixme include/reddav.php:92 - public $owner_id; - // @fixme include/reddav.php:283 + /** + * channel_id of the current visited path. Set in RedDirectory::getDir(). + * + * @var int + */ + public $owner_id = 0; + /** + * channel_name of the current visited path. Set in RedDirectory::getDir(). + * + * Used for creating the path in cloud/ + * + * @var string + */ public $owner_nick = ''; - // @fixme mod/cloud.php:66 - public $timezone; + /** + * Timezone from the visiting channel's channel_timezone. + * + * Used in @ref RedBrowser + * + * @var string + */ + protected $timezone = ''; + /** + * @brief Validates a username and password. + * + * Guest access is granted with the password "+++". * + * @see DAV\Auth\Backend\AbstractBasic::validateUserPass * @param string $username * @param string $password + * @return bool */ protected function validateUserPass($username, $password) { - if (trim($password) === '+++') { - logger('reddav: validateUserPass: guest ' . $username); + logger('(DAV): RedBasicAuth::validateUserPass(): guest ' . $username); return true; } require_once('include/auth.php'); $record = account_verify_password($username, $password); if ($record && $record['account_default_channel']) { - $r = q("select * from channel where channel_account_id = %d and channel_id = %d limit 1", + $r = q("SELECT * FROM channel WHERE channel_account_id = %d AND channel_id = %d LIMIT 1", intval($record['account_id']), intval($record['account_default_channel']) ); if ($r) { - $this->currentUser = $r[0]['channel_address']; - $this->channel_name = $r[0]['channel_address']; - $this->channel_id = $r[0]['channel_id']; - $this->channel_hash = $this->observer = $r[0]['channel_hash']; - $_SESSION['uid'] = $r[0]['channel_id']; - $_SESSION['account_id'] = $r[0]['channel_account_id']; - $_SESSION['authenticated'] = true; - return true; + return $this->setAuthenticated($r[0]); } } - $r = q("select * from channel where channel_address = '%s' limit 1", + $r = q("SELECT * FROM channel WHERE channel_address = '%s' LIMIT 1", dbesc($username) ); if ($r) { - $x = q("select * from account where account_id = %d limit 1", + $x = q("SELECT account_flags, account_salt, account_password FROM account WHERE account_id = %d LIMIT 1", intval($r[0]['channel_account_id']) ); if ($x) { + // @fixme this foreach should not be needed? foreach ($x as $record) { if (($record['account_flags'] == ACCOUNT_OK) || ($record['account_flags'] == ACCOUNT_UNVERIFIED) && (hash('whirlpool', $record['account_salt'] . $password) === $record['account_password'])) { logger('(DAV) RedBasicAuth: password verified for ' . $username); - $this->currentUser = $r[0]['channel_address']; - $this->channel_name = $r[0]['channel_address']; - $this->channel_id = $r[0]['channel_id']; - $this->channel_hash = $this->observer = $r[0]['channel_hash']; - $_SESSION['uid'] = $r[0]['channel_id']; - $_SESSION['account_id'] = $r[0]['channel_account_id']; - $_SESSION['authenticated'] = true; - return true; + return $this->setAuthenticated($r[0]); } } } @@ -1051,12 +1091,68 @@ class RedBasicAuth extends DAV\Auth\Backend\AbstractBasic { return false; } + /** + * @brief Sets variables and session parameters after successfull authentication. + * + * @param array $r + * Array with the values for the authenticated channel. + * @return bool + */ + protected function setAuthenticated($r) { + $this->channel_name = $r['channel_address']; + $this->channel_id = $r['channel_id']; + $this->channel_hash = $this->observer = $r['channel_hash']; + $_SESSION['uid'] = $r['channel_id']; + $_SESSION['account_id'] = $r['channel_account_id']; + $_SESSION['authenticated'] = true; + return true; + } + + /** + * Sets the channel_name from the currently logged-in channel. + * + * @param string $name + * The channel's name + */ public function setCurrentUser($name) { - $this->currentUser = $name; + $this->channel_name = $name; + } + /** + * Returns information about the currently logged-in channel. + * + * If nobody is currently logged in, this method should return null. + * + * @see DAV\Auth\Backend\AbstractBasic::getCurrentUser + * @return string|null + */ + public function getCurrentUser() { + return $this->channel_name; } /** - * @brief Set browser plugin. + * @brief Sets the timezone from the channel in RedBasicAuth. + * + * Set in mod/cloud.php if the channel has a timezone set. + * + * @param string $timezone + * The channel's timezone. + * @return void + */ + public function setTimezone($timezone) { + $this->timezone = $timezone; + } + /** + * @brief Returns the timezone. + * + * @return string + * Return the channel's timezone. + */ + public function getTimezone() { + return $this->timezone; + } + + /** + * @brief Set browser plugin for SabreDAV. * * @see RedBrowser::set_writeable() * @param DAV\Browser\Plugin $browser @@ -1065,8 +1161,12 @@ class RedBasicAuth extends DAV\Auth\Backend\AbstractBasic { $this->browser = $browser; } - // internal? logging function - function log() { + /** + * Prints out all RedBasicAuth variables to logger(). + * + * @return void + */ + public function log() { logger('dav: auth: channel_name ' . $this->channel_name, LOGGER_DATA); logger('dav: auth: channel_id ' . $this->channel_id, LOGGER_DATA); logger('dav: auth: channel_hash ' . $this->channel_hash, LOGGER_DATA); @@ -1080,13 +1180,23 @@ class RedBasicAuth extends DAV\Auth\Backend\AbstractBasic { /** - * RedBrowser class. + * @brief RedBrowser class. * + * RedBrowser is a SabreDAV server-plugin to provide a view to the DAV in + * the browser */ class RedBrowser extends DAV\Browser\Plugin { + /** + * @var RedBasicAuth + */ private $auth; + /** + * @brief Constructor for RedBrowser. + * + * @param RedBasicAuth &$auth + */ function __construct(&$auth) { $this->auth = $auth; $this->enableAssets = false; @@ -1096,6 +1206,7 @@ class RedBrowser extends DAV\Browser\Plugin { // directory and who the owner and observer are. So we add a pointer to the browser into the auth module and vice // versa. Then when we've figured out what directory is actually being accessed, we call the following function // to decide whether or not to show web elements which include writeable objects. + // @todo Maybe this can be solved with some $server->subscribeEvent()? function set_writeable() { if (! $this->auth->owner_id) { $this->enablePost = false; @@ -1117,8 +1228,8 @@ class RedBrowser extends DAV\Browser\Plugin { // (owner_id = channel_id) is visitor owner of this directory? $is_owner = ((local_user() && $this->auth->owner_id == local_user()) ? true : false); - if ($this->auth->timezone) - date_default_timezone_set($this->auth->timezone); + if ($this->auth->getTimezone()) + date_default_timezone_set($this->auth->getTimezone()); require_once('include/conversation.php'); @@ -1237,7 +1348,7 @@ class RedBrowser extends DAV\Browser\Plugin { // put the array for this file together $ft['attachId'] = $this->findAttachIdByHash($attachHash); - $ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->channel_name; + $ft['fileStorageUrl'] = substr($fullPath, 0, strpos($fullPath, "cloud/")) . "filestorage/" . $this->auth->getCurrentUser(); $ft['icon'] = $icon; $ft['attachIcon'] = (($size) ? $attachIcon : ''); // @todo Should this be an item value, not a global one? diff --git a/include/statistics_fns.php b/include/statistics_fns.php new file mode 100644 index 000000000..4f72e6615 --- /dev/null +++ b/include/statistics_fns.php @@ -0,0 +1,73 @@ +<?php /** @file */ + +function update_channels_total_stat() { + $r = q("select count(channel_id) as channels_total from channel left join account on account_id = channel_account_id + where account_flags = 0 "); + if($r) { + $channels_total_stat = intval($r[0]['channels_total']); + set_config('system','channels_total_stat',$channels_total_stat); + } else { + set_config('system','channels_total_stat',null); + } +} + +function update_channels_active_halfyear_stat() { + $r = q("select channel_id from channel left join account on account_id = channel_account_id + where account_flags = 0 and account_lastlog > UTC_TIMESTAMP - INTERVAL 6 MONTH"); + if($r) { + $s = ''; + foreach($r as $rr) { + if($s) + $s .= ','; + $s .= intval($rr['channel_id']); + } + $x = q("select uid from item where uid in ( $s ) and (item_flags & %d) and created > UTC_TIMESTAMP - INTERVAL 6 MONTH group by uid", + intval(ITEM_WALL) + ); + if($x) { + $channels_active_halfyear_stat = count($x); + set_config('system','channels_active_halfyear_stat',$channels_active_halfyear_stat); + } else { + set_config('system','channels_active_halfyear_stat',null); + } + } else { + set_config('system','channels_active_halfyear_stat',null); + } +} + +function update_channels_active_monthly_stat() { + $r = q("select channel_id from channel left join account on account_id = channel_account_id + where account_flags = 0 and account_lastlog > UTC_TIMESTAMP - INTERVAL 1 MONTH"); + if($r) { + $s = ''; + foreach($r as $rr) { + if($s) + $s .= ','; + $s .= intval($rr['channel_id']); + } + $x = q("select uid from item where uid in ( $s ) and ( item_flags & %d ) and created > UTC_TIMESTAMP - INTERVAL 1 MONTH group by uid", + intval(ITEM_WALL) + ); + if($x) { + $channels_active_monthly_stat = count($x); + set_config('system','channels_active_monthly_stat',$channels_active_monthly_stat); + } else { + set_config('system','channels_active_monthly_stat',null); + } + } else { + set_config('system','channels_active_monthly_stat',null); + } +} + +function update_local_posts_stat() { + $posts = q("SELECT COUNT(*) AS local_posts FROM `item` WHERE (item_flags & %d) ", + intval(ITEM_WALL) ); + if (is_array($posts)) { + $local_posts_stat = intval($posts[0]["local_posts"]); + set_config('system','local_posts_stat',$local_posts_stat); + } else { + set_config('system','local_posts_stat',null); + } +} + + diff --git a/include/zot.php b/include/zot.php index 828194c3a..3d59f00f3 100644 --- a/include/zot.php +++ b/include/zot.php @@ -1674,8 +1674,6 @@ function process_location_delivery($sender,$arr,$deliveries) { logger('process_location_delivery: results: ' . print_r($x,true), LOGGER_DATA); } -// We need to merge this code with that in the import_xchan function so as to make it -// easier to maintain changes. function sync_locations($sender,$arr,$absolute = false) { |