Merge branch 'origin' into 'master'

marge from origin 4.1

See merge request harukin/core!47
This commit is contained in:
harukin
2019-03-21 21:43:10 +09:00
52 changed files with 947 additions and 258 deletions
+18 -20
View File
@@ -142,12 +142,10 @@ function create_account($arr) {
$invite_code = ((x($arr,'invite_code')) ? notags(trim($arr['invite_code'])) : '');
$email = ((x($arr,'email')) ? notags(punify(trim($arr['email']))) : '');
$password = ((x($arr,'password')) ? trim($arr['password']) : '');
$password2 = ((x($arr,'password2')) ? trim($arr['password2']) : '');
$parent = ((x($arr,'parent')) ? intval($arr['parent']) : 0 );
$flags = ((x($arr,'account_flags')) ? intval($arr['account_flags']) : ACCOUNT_OK);
$roles = ((x($arr,'account_roles')) ? intval($arr['account_roles']) : 0 );
$expires = ((x($arr,'expires')) ? intval($arr['expires']) : NULL_DATE);
$techlevel = ((array_key_exists('techlevel',$arr)) ? intval($arr['techlevel']) : intval(get_config('system','techlevel')));
$default_service_class = get_config('system','default_service_class');
@@ -264,9 +262,8 @@ function create_account($arr) {
function verify_email_address($arr) {
if(array_key_exists('resend',$arr)) {
$email = $arr['email'];
$a = q("select * from account where account_email = '%s' limit 1",
dbesc($arr['email'])
dbesc($arr['email'])
);
if(! ($a && ($a[0]['account_flags'] & ACCOUNT_UNVERIFIED))) {
return false;
@@ -285,7 +282,7 @@ function verify_email_address($arr) {
else {
$hash = random_string(24);
$r = q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ",
q("INSERT INTO register ( hash, created, uid, password, lang ) VALUES ( '%s', '%s', %d, '%s', '%s' ) ",
dbesc($hash),
dbesc(datetime_convert()),
intval($arr['account']['account_id']),
@@ -304,7 +301,7 @@ function verify_email_address($arr) {
'$email' => $arr['email'],
'$uid' => $account['account_id'],
'$hash' => $hash,
'$details' => $details
'$details' => ''
]
);
@@ -318,9 +315,7 @@ function verify_email_address($arr) {
pop_lang();
if($res)
$delivered ++;
else
if(! $res)
logger('send_reg_approval_email: failed to account_id: ' . $arr['account']['account_id']);
return $res;
@@ -442,16 +437,17 @@ function account_allow($hash) {
if(! $account)
return $ret;
$r = q("DELETE FROM register WHERE hash = '%s'",
q("DELETE FROM register WHERE hash = '%s'",
dbesc($register[0]['hash'])
);
$r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_BLOCKED),
intval(ACCOUNT_BLOCKED),
intval($register[0]['uid'])
);
$r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_PENDING),
intval(ACCOUNT_PENDING),
intval($register[0]['uid'])
@@ -516,11 +512,11 @@ function account_deny($hash) {
if(! $account)
return false;
$r = q("DELETE FROM account WHERE account_id = %d",
q("DELETE FROM account WHERE account_id = %d",
intval($register[0]['uid'])
);
$r = q("DELETE FROM register WHERE id = %d",
q("DELETE FROM register WHERE id = %d",
dbesc($register[0]['id'])
);
notice( sprintf(t('Registration revoked for %s'), $account[0]['account_email']) . EOL);
@@ -551,21 +547,23 @@ function account_approve($hash) {
if(! $account)
return $ret;
$r = q("DELETE FROM register WHERE hash = '%s' and password = 'verify'",
q("DELETE FROM register WHERE hash = '%s' and password = 'verify'",
dbesc($register[0]['hash'])
);
$r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_BLOCKED),
intval(ACCOUNT_BLOCKED),
intval($register[0]['uid'])
);
$r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_PENDING),
intval(ACCOUNT_PENDING),
intval($register[0]['uid'])
);
$r = q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
q("update account set account_flags = (account_flags & ~%d) where (account_flags & %d)>0 and account_id = %d",
intval(ACCOUNT_UNVERIFIED),
intval(ACCOUNT_UNVERIFIED),
intval($register[0]['uid'])
@@ -620,7 +618,7 @@ function downgrade_accounts() {
foreach($r as $rr) {
if(($basic) && ($rr['account_service_class']) && ($rr['account_service_class'] != $basic)) {
$x = q("UPDATE account set account_service_class = '%s', account_expires = '%s'
q("UPDATE account set account_service_class = '%s', account_expires = '%s'
where account_id = %d",
dbesc($basic),
dbesc(NULL_DATE),
@@ -631,7 +629,7 @@ function downgrade_accounts() {
logger('downgrade_accounts: Account id ' . $rr['account_id'] . ' downgraded.');
}
else {
$x = q("UPDATE account SET account_flags = (account_flags | %d) where account_id = %d",
q("UPDATE account SET account_flags = (account_flags | %d) where account_id = %d",
intval(ACCOUNT_EXPIRED),
intval($rr['account_id'])
);
+1 -1
View File
@@ -84,7 +84,7 @@ function populate_acl($defaults = null,$show_jotnets = true, $emptyACL_descripti
);
if($r) {
foreach($r as $rv) {
$selected = (($single_group && 'vp.' . $rr['hash'] === $allow_gid[0]) ? ' selected = "selected" ' : '');
$selected = (($single_group && 'vp.' . $rv['profile_guid'] === $allow_gid[0]) ? ' selected = "selected" ' : '');
$groups .= '<option id="' . 'vp' . $rv['id'] . '" value="' . 'vp.' . $rv['profile_guid'] . '"' . $selected . '>' . t('Profile','acl') . ' ' . $rv['profile_name'] . '</option>' . "\r\n";
}
}
+13 -19
View File
@@ -321,7 +321,6 @@ function attach_can_view_folder($uid,$ob_hash,$folder_hash) {
$sql_extra = permissions_sql($uid,$ob_hash);
$hash = $folder_hash;
$result = false;
if(! $folder_hash) {
return perm_is_allowed($uid,$ob_hash,'view_storage');
@@ -352,7 +351,7 @@ function attach_can_view_folder($uid,$ob_hash,$folder_hash) {
* @param string $hash
* @param string $observer_hash
* @param int $rev (optional) revision default 0
* @return associative array with everything except data
* @return array (associative) with everything except data
* * \e boolean \b success boolean true or false
* * \e string \b message (optional) only when success is false
* * \e array \b data array of attach DB entry without data component
@@ -1224,7 +1223,7 @@ function attach_mkdir($channel, $observer_hash, $arr = null) {
$ret['success'] = true;
// update the parent folder's lastmodified timestamp
$e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
dbesc($created),
dbesc($arr['folder']),
intval($channel_id)
@@ -1270,8 +1269,6 @@ function attach_mkdirp($channel, $observer_hash, $arr = null) {
$ret = array('success' => false);
$channel_id = $channel['channel_id'];
$sql_options = '';
$basepath = 'store/' . $channel['channel_address'];
logger('basepath: ' . $basepath);
@@ -1374,7 +1371,7 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi
}
}
$x = q("update attach set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where hash = '%s' and uid = %d",
q("update attach set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where hash = '%s' and uid = %d",
dbesc($allow_cid),
dbesc($allow_gid),
dbesc($deny_cid),
@@ -1383,7 +1380,7 @@ function attach_change_permissions($channel_id, $resource, $allow_cid, $allow_gi
intval($channel_id)
);
if($r[0]['is_photo']) {
$x = q("update photo set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where resource_id = '%s' and uid = %d",
q("update photo set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where resource_id = '%s' and uid = %d",
dbesc($allow_cid),
dbesc($allow_gid),
dbesc($deny_cid),
@@ -1482,7 +1479,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
}
// delete from database
$z = q("DELETE FROM attach WHERE hash = '%s' AND uid = %d",
q("DELETE FROM attach WHERE hash = '%s' AND uid = %d",
dbesc($resource),
intval($channel_id)
);
@@ -1493,7 +1490,7 @@ function attach_delete($channel_id, $resource, $is_photo = 0) {
// update the parent folder's lastmodified timestamp
$e = q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
q("UPDATE attach SET edited = '%s' WHERE hash = '%s' AND uid = %d",
dbesc(datetime_convert()),
dbesc($r[0]['folder']),
intval($channel_id)
@@ -1815,7 +1812,7 @@ function file_activity($channel_id, $object, $allow_cid, $allow_gid, $deny_cid,
$u_jsonobject = json_encode($object);
//we have got the relevant info - delete the old item before we create the new one
$z = q("DELETE FROM item WHERE obj_type = '%s' AND verb = '%s' AND mid = '%s'",
q("DELETE FROM item WHERE obj_type = '%s' AND verb = '%s' AND mid = '%s'",
dbesc(ACTIVITY_OBJ_FILE),
dbesc(ACTIVITY_POST),
dbesc($y[0]['mid'])
@@ -1946,7 +1943,6 @@ function attach_recursive_perms($arr_allow_cid, $arr_allow_gid, $arr_deny_cid, $
$ret = array();
$parent_arr = array();
$count_values = array();
$poster = App::get_observer();
//lookup all channels in sharee group and add them to sharee $arr_allow_cid
if($arr_allow_gid) {
@@ -2351,7 +2347,6 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
if(! $n)
return false;
$newdirname = $n[0]['filename'];
$newalbumname = $n[0]['display_path'];
$newstorepath = dbunescbin($n[0]['content']) . '/' . $resource_id;
}
@@ -2359,7 +2354,6 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
// root directory
$newdirname = EMPTY_STR;
$newalbumname = EMPTY_STR;
$newstorepath = 'store/' . $c['channel_address'] . '/' . $resource_id;
}
@@ -2428,7 +2422,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
}
}
$t = q("update attach set content = '%s', folder = '%s', filename = '%s' where id = %d",
q("update attach set content = '%s', folder = '%s', filename = '%s' where id = %d",
dbescbin($newstorepath),
dbesc($new_folder_hash),
dbesc($filename),
@@ -2438,7 +2432,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
$x = attach_syspaths($channel_id,$resource_id);
$t1 = q("update attach set os_path = '%s', display_path = '%s' where id = %d",
q("update attach set os_path = '%s', display_path = '%s' where id = %d",
dbesc($x['os_path']),
dbesc($x['path']),
intval($r[0]['id'])
@@ -2446,7 +2440,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
if($r[0]['is_photo']) {
$t = q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s'
q("update photo set album = '%s', filename = '%s', os_path = '%s', display_path = '%s'
where resource_id = '%s' and uid = %d",
dbesc($newalbumname),
dbesc($filename),
@@ -2456,7 +2450,7 @@ function attach_move($channel_id, $resource_id, $new_folder_hash) {
intval($channel_id)
);
$t = q("update photo set content = '%s' where resource_id = '%s' and uid = %d and imgscale = 0",
q("update photo set content = '%s' where resource_id = '%s' and uid = %d and imgscale = 0",
dbescbin($newstorepath),
dbesc($resource_id),
intval($channel_id)
@@ -2587,12 +2581,12 @@ function attach_upgrade() {
foreach($r as $rv) {
$x = attach_syspaths($rv['uid'],$rv['hash']);
if($x) {
$w = q("update attach set os_path = '%s', display_path = '%s' where id = %d",
q("update attach set os_path = '%s', display_path = '%s' where id = %d",
dbesc($x['os_path']),
dbesc($x['path']),
intval($rv['id'])
);
$y = q("update photo set os_path = '%s', display_path = '%s' where uid = %d and resource_id = '%s'",
q("update photo set os_path = '%s', display_path = '%s' where uid = %d and resource_id = '%s'",
dbesc($x['os_path']),
dbesc($x['path']),
intval($rv['uid']),
+22 -1
View File
@@ -117,6 +117,26 @@ function tryzrlvideo($match) {
return '<video ' . $poster . ' controls="controls" preload="none" src="' . str_replace(' ','%20',$link) . '" style="width:100%; max-width:' . App::$videowidth . 'px"><a href="' . str_replace(' ','%20',$link) . '">' . $link . '</a></video>';
}
function videowithopts($match) {
$link = $match[2];
$zrl = is_matrix_url($link);
if($zrl)
$link = zid($link);
$attributes = $match[1];
$poster = "";
preg_match("/poster='(.*?)'/ism", $attributes, $matches);
if ($matches[1] != "")
$poster = 'poster="' . (($zrl) ? zid($matches[1]) : $matches[1]) . '"';
return '<video ' . $poster . ' controls="controls" preload="none" src="' . str_replace(' ','%20',$link) . '" style="width:100%; max-width:' . App::$videowidth . 'px"><a href="' . str_replace(' ','%20',$link) . '">' . $link . '</a></video>';
}
// [noparse][i]italic[/i][/noparse] turns into
// [noparse][ i ]italic[ /i ][/noparse],
// to hide them from parser.
@@ -1251,12 +1271,14 @@ function bbcode($Text, $options = []) {
// html5 video and audio
if (strpos($Text,'[/video]') !== false) {
$Text = preg_replace_callback("/\[video (.*?)\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/video\]/ism", 'videowithopts', $Text);
$Text = preg_replace_callback("/\[video\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/video\]/ism", 'tryzrlvideo', $Text);
}
if (strpos($Text,'[/audio]') !== false) {
$Text = preg_replace_callback("/\[audio\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mp3|opus|m4a))\[\/audio\]/ism", 'tryzrlaudio', $Text);
}
if (strpos($Text,'[/zvideo]') !== false) {
$Text = preg_replace_callback("/\[zvideo (.*?)\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/zvideo\]/ism", 'videowithopts', $Text);
$Text = preg_replace_callback("/\[zvideo\](.*?\.(ogg|ogv|oga|ogm|webm|mp4|mpeg|mpg))\[\/zvideo\]/ism", 'tryzrlvideo', $Text);
}
if (strpos($Text,'[/zaudio]') !== false) {
@@ -1360,4 +1382,3 @@ function bbcode($Text, $options = []) {
return $Text;
}
+13 -1
View File
@@ -948,6 +948,18 @@ function identity_basic_export($channel_id, $sections = null) {
}
$ret['app'] = $r;
}
$r = q("select * from app where app_channel = %d and app_system = 1",
intval($channel_id)
);
if($r) {
for($x = 0; $x < count($r); $x ++) {
$r[$x]['term'] = q("select * from term where otype = %d and oid = %d",
intval(TERM_OBJ_APP),
intval($r[$x]['id'])
);
}
$ret['sysapp'] = $r;
}
}
if(in_array('chatrooms',$sections)) {
@@ -1439,7 +1451,7 @@ function profile_edit_menu($uid) {
* @param boolean $show_connect (optional) default true
* @param mixed $zcard (optional) default false
*
* @return HTML string suitable for sidebar inclusion
* @return string (HTML) suitable for sidebar inclusion
* Exceptions: Returns empty string if passed $profile is wrong type or not populated
*/
function profile_sidebar($profile, $block = 0, $show_connect = true, $zcard = false) {
+1
View File
@@ -119,6 +119,7 @@ function new_contact($uid,$url,$channel,$interactive = false, $confirm = false)
if( array_key_exists('permissions',$j) && array_key_exists('data',$j['permissions'])) {
$permissions = crypto_unencapsulate(array(
'data' => $j['permissions']['data'],
'alg' => $j['permissions']['alg'],
'key' => $j['permissions']['key'],
'iv' => $j['permissions']['iv']),
$channel['channel_prvkey']);
+36
View File
@@ -305,3 +305,39 @@ function ping_site($url) {
return $ret;
}
function z6_discover() {
// find unregistered zot6 clone hublocs
$c = q("select channel_hash, portable_id from channel where channel_deleted = 0");
if ($c) {
foreach ($c as $entry) {
$q1 = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_deleted = 0 and site_dead = 0 and hubloc_hash = '%s' and hubloc_url != '%s'",
dbesc($entry['channel_hash']),
dbesc(z_root())
);
if (! $q1) {
// channel has no zot clones
continue;
}
// does this particular server have a zot6 clone registered on our site for this channel?
foreach ($q1 as $q) {
$q2 = q("select * from hubloc left join site on hubloc_url = site_url where hubloc_deleted = 0 and site_dead = 0 and hubloc_hash = '%s' and hubloc_url = '%s'",
dbesc($entry['portable_id']),
dbesc($q['hubloc_url'])
);
if ($q2) {
continue;
}
// zot6 hubloc not found.
if(strpos($entry['site_project'],'hubzilla') !== false && version_compare($entry['site_version'],'4.0') >= 0) {
// probe and store results - only for zot6 (over-ride the zot default)
discover_by_webbie($entry['hubloc_addr'],'zot6');
}
}
}
}
}
+87 -1
View File
@@ -147,7 +147,9 @@ function import_config($channel, $configs) {
foreach($configs as $config) {
unset($config['id']);
$config['uid'] = $channel['channel_id'];
if($config['cat'] === 'system' && $config['k'] === 'import_system_apps') {
continue;
}
create_table_from_array('pconfig', $config);
}
@@ -364,6 +366,9 @@ function import_apps($channel, $apps) {
if($channel && $apps) {
foreach($apps as $app) {
if(array_key_exists('app_system',$app) && intval($app['app_system']))
continue;
$term = ((array_key_exists('term',$app) && is_array($app['term'])) ? $app['term'] : null);
unset($app['id']);
@@ -413,6 +418,9 @@ function sync_apps($channel, $apps) {
$exists = false;
$term = ((array_key_exists('term',$app)) ? $app['term'] : null);
if(array_key_exists('app_system',$app) && intval($app['app_system']))
continue;
$x = q("select * from app where app_id = '%s' and app_channel = %d limit 1",
dbesc($app['app_id']),
intval($channel['channel_id'])
@@ -504,6 +512,84 @@ function sync_apps($channel, $apps) {
}
}
/**
* @brief Import system apps.
* System apps from the original server may not exist on this system
* (e.g. apps associated with addons that are not installed here).
* Check the system apps that were provided in the import file to see if they
* exist here and if so, install them locally. Preserve categories that
* might have been added by this channel on the other server.
* Do not use any paths from the original as they will point to a different server.
* @param array $channel
* @param array $apps
*/
function import_sysapps($channel, $apps) {
if($channel && $apps) {
$sysapps = \Zotlabs\Lib\Apps::get_system_apps(false);
foreach($apps as $app) {
if(array_key_exists('app_system',$app) && (! intval($app['app_system'])))
continue;
$term = ((array_key_exists('term',$app) && is_array($app['term'])) ? $app['term'] : null);
foreach($sysapps as $sysapp) {
if($app['app_id'] === hash('whirlpool',$sysapp['app_name'])) {
// install this app on this server
$newapp = $sysapp;
$newapp['uid'] = $channel['channel_id'];
$newapp['guid'] = hash('whirlpool',$newapp['name']);
$installed = q("select id from app where app_id = '%s' and app_channel = %d limit 1",
dbesc($newapp['guid']),
intval($channel['channel_id'])
);
if($installed) {
break;
}
$newapp['system'] = 1;
if($term) {
$s = EMPTY_STR;
foreach($term as $t) {
if($s) {
$s .= ',';
}
$s .= $t['term'];
}
$newapp['categories'] = $s;
}
\Zotlabs\Lib\Apps::app_install($channel['channel_id'],$newapp);
}
}
}
}
}
/**
* @brief Sync system apps.
*
* @param array $channel
* @param array $apps
*/
function sync_sysapps($channel, $apps) {
if($channel && $apps) {
// we do not currently sync system apps
}
}
/**
* @brief Import chatrooms.
*
+12 -2
View File
@@ -763,11 +763,11 @@ function get_item_elements($x,$allow_code = false) {
// check the supplied signature against the supplied content.
// Note that we will purify the content which could change it.
$r = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1",
$r = q("select xchan_pubkey, xchan_network from xchan where xchan_hash = '%s' limit 1",
dbesc($arr['author_xchan'])
);
if($r) {
if($r[0]['xchan_pubkey']) {
if($r[0]['xchan_pubkey'] && $r[0]['xchan_network'] === 'zot') {
if(rsa_verify($x['body'],base64url_decode($arr['sig']),$r[0]['xchan_pubkey'])) {
$arr['item_verified'] = 1;
}
@@ -914,6 +914,16 @@ function import_author_xchan($x) {
if(array_key_exists('network',$x) && $x['network'] === 'zot')
return $y;
// perform zot6 discovery
if($x['url']) {
$y = discover_by_webbie($x['url'],'zot6');
if($y) {
return $y;
}
}
if($x['network'] === 'rss') {
$y = import_author_rss($x);
}
+7 -5
View File
@@ -42,6 +42,10 @@ function nav($template = 'default') {
require_once('include/conversation.php');
$nav_apps = [];
$navbar_apps = [];
$channel_apps = [];
$channel_apps[] = channel_apps($is_owner, App::$profile['channel_address']);
@@ -179,7 +183,6 @@ function nav($template = 'default') {
$search_form_action = 'search';
}
$nav['search'] = ['search', t('Search'), "", t('Search site @name, !forum, #tag, ?docs, content'), $search_form_action];
/**
@@ -378,16 +381,15 @@ function channel_apps($is_owner = false, $nickname = null) {
if(App::$is_sys)
return '';
if(! get_pconfig($uid, 'system', 'channelapps','1'))
return '';
$channel = App::get_channel();
if($channel && is_null($nickname))
$nickname = $channel['channel_address'];
$uid = ((App::$profile['profile_uid']) ? App::$profile['profile_uid'] : local_channel());
$account_id = ((App::$profile['profile_uid']) ? App::$profile['channel_account_id'] : App::$channel['channel_account_id']);
if(! get_pconfig($uid, 'system', 'channelapps','1'))
return;
if($uid == local_channel()) {
return;
+8 -5
View File
@@ -874,13 +874,16 @@ function xml2array($contents, $namespaces = true, $get_attributes=1, $priority =
}
function email_header_encode($in_str, $charset = 'UTF-8') {
function email_header_encode($in_str, $charset = 'UTF-8', $header = 'Subject') {
$out_str = $in_str;
$need_to_convert = false;
for($x = 0; $x < strlen($in_str); $x ++) {
if((ord($in_str[$x]) == 0) || ((ord($in_str[$x]) > 128))) {
$need_to_convert = true;
break;
}
}
@@ -892,11 +895,11 @@ function email_header_encode($in_str, $charset = 'UTF-8') {
// define start delimimter, end delimiter and spacer
$end = "?=";
$start = "=?" . $charset . "?B?";
$spacer = $end . "\r\n " . $start;
$spacer = $end . PHP_EOL . " " . $start;
// determine length of encoded text within chunks
// and ensure length is even
$length = 75 - strlen($start) - strlen($end);
$length = 75 - strlen($start) - strlen($end) - (strlen($header) + 2);
/*
[EDIT BY danbrown AT php DOT net: The following
@@ -1796,8 +1799,8 @@ function z_mail($params) {
$messageHeader =
$params['additionalMailHeader'] .
"From: $fromName <{$params['fromEmail']}>\n" .
"Reply-To: $fromName <{$params['replyTo']}>\n" .
"From: $fromName <{$params['fromEmail']}>" . PHP_EOL .
"Reply-To: $fromName <{$params['replyTo']}>" . PHP_EOL .
"Content-Type: text/plain; charset=UTF-8";
// send the message
+212 -66
View File
@@ -306,6 +306,7 @@ function change_channel($change_channel) {
*
* @return string additional SQL where statement
*/
function permissions_sql($owner_id, $remote_observer = null, $table = '') {
$local_channel = local_channel();
@@ -316,7 +317,7 @@ function permissions_sql($owner_id, $remote_observer = null, $table = '') {
* default permissions - anonymous user
*/
if($table)
if ($table)
$table .= '.';
$sql = " AND {$table}allow_cid = ''
@@ -329,38 +330,63 @@ function permissions_sql($owner_id, $remote_observer = null, $table = '') {
* Profile owner - everything is visible
*/
if(($local_channel) && ($local_channel == $owner_id)) {
$sql = '';
if (($local_channel) && ($local_channel == $owner_id)) {
return EMPTY_STR;
}
/**
* Authenticated visitor. Unless pre-verified,
* check that the contact belongs to this $owner_id
* and load the groups the visitor belongs to.
* If pre-verified, the caller is expected to have already
* done this and passed the groups into this function.
* Authenticated visitor.
*/
else {
$observer = ((! is_null($remote_observer)) ? $remote_observer : get_observer_hash());
if($observer) {
$groups = init_groups_visitor($observer);
$gs = '<<>>'; // should be impossible to match
if ($observer) {
if(is_array($groups) && count($groups)) {
foreach($groups as $g)
$gs .= '|<' . $g . '>';
$sec = get_security_ids($owner_id,$observer);
// always allow the channel owner, even if authenticated as a visitor
if ($sec['channel_id']) {
foreach ($sec['channel_id'] as $ch) {
if ($observer === $ch) {
return EMPTY_STR;
}
}
}
if (is_array($sec['allow_cid']) && count($sec['allow_cid'])) {
$ca = [];
foreach ($sec['allow_cid'] as $c) {
$ca[] = '<' . $c . '>';
}
$cs = implode('|',$ca);
}
else {
$cs = '<<>>'; // should be impossible to match
}
if (is_array($sec['allow_gid']) && count($sec['allow_gid'])) {
$ga = [];
foreach ($sec['allow_gid'] as $g) {
$ga[] = '<' . $g . '>';
}
$gs = implode('|',$ga);
}
else {
$gs = '<<>>'; // should be impossible to match
}
$regexop = db_getfunc('REGEXP');
$sql = sprintf(
" AND ( NOT ({$table}deny_cid like '%s' OR {$table}deny_gid $regexop '%s')
AND ( {$table}allow_cid like '%s' OR {$table}allow_gid $regexop '%s' OR ( {$table}allow_cid = '' AND {$table}allow_gid = '') )
" AND ( NOT ({$table}deny_cid $regexop '%s' OR {$table}deny_gid $regexop '%s')
AND ( {$table}allow_cid $regexop '%s' OR {$table}allow_gid $regexop '%s' OR ( {$table}allow_cid = '' AND {$table}allow_gid = '') )
)
",
dbesc(protect_sprintf( '%<' . $observer . '>%')),
dbesc($cs),
dbesc($gs),
dbesc(protect_sprintf( '%<' . $observer . '>%')),
dbesc($cs),
dbesc($gs)
);
}
@@ -377,6 +403,7 @@ function permissions_sql($owner_id, $remote_observer = null, $table = '') {
*
* @return string additional SQL where statement
*/
function item_permissions_sql($owner_id, $remote_observer = null) {
$local_channel = local_channel();
@@ -398,37 +425,59 @@ function item_permissions_sql($owner_id, $remote_observer = null) {
}
/**
* Authenticated visitor. Unless pre-verified,
* check that the contact belongs to this $owner_id
* and load the groups the visitor belongs to.
* If pre-verified, the caller is expected to have already
* done this and passed the groups into this function.
* Authenticated visitor.
*/
else {
$observer = (($remote_observer) ? $remote_observer : get_observer_hash());
if($observer) {
$observer = (($remote_observer) ? $remote_observer : get_observer_hash());
$s = scopes_sql($owner_id,$observer);
if($observer) {
$groups = init_groups_visitor($observer);
$scope = scopes_sql($owner_id,$observer);
$sec = get_security_ids($owner_id,$observer);
$gs = '<<>>'; // should be impossible to match
// always allow the channel owner, even if authenticated as a visitor
if(is_array($groups) && count($groups)) {
foreach($groups as $g)
$gs .= '|<' . $g . '>';
if($sec['channel_id']) {
foreach($sec['channel_id'] as $ch) {
if($observer === $ch) {
return EMPTY_STR;
}
}
}
if (is_array($sec['allow_cid']) && count($sec['allow_cid'])) {
$ca = [];
foreach ($sec['allow_cid'] as $c) {
$ca[] = '<' . $c . '>';
}
$cs = implode('|',$ca);
}
else {
$cs = '<<>>'; // should be impossible to match
}
if (is_array($sec['allow_gid']) && count($sec['allow_gid'])) {
$ga = [];
foreach ($sec['allow_gid'] as $g) {
$ga[] = '<' . $g . '>';
}
$gs = implode('|',$ga);
}
else {
$gs = '<<>>'; // should be impossible to match
}
$regexop = db_getfunc('REGEXP');
$sql = sprintf(
" AND (( NOT (deny_cid like '%s' OR deny_gid $regexop '%s')
AND ( allow_cid like '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 ))
) OR ( item_private = 1 $s ))
" AND (( NOT (deny_cid $regexop '%s' OR deny_gid $regexop '%s')
AND ( allow_cid $regexop '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 ))
) OR ( item_private = 1 $scope ))
",
dbesc(protect_sprintf( '%<' . $observer . '>%')),
dbesc($cs),
dbesc($gs),
dbesc(protect_sprintf( '%<' . $observer . '>%')),
dbesc($cs),
dbesc($gs)
);
}
@@ -465,40 +514,57 @@ function scopes_sql($uid,$observer) {
}
/**
* @param string $observer_hash
*
* @return string additional SQL where statement
*/
function public_permissions_sql($observer_hash) {
$groups = init_groups_visitor($observer_hash);
$owner_id = 0;
$gs = '<<>>'; // should be impossible to match
if ($observer_hash) {
$sec = get_security_ids($owner_id,$observer_hash);
if (is_array($sec['allow_cid']) && count($sec['allow_cid'])) {
$ca = [];
foreach ($sec['allow_cid'] as $c) {
$ca[] = '<' . $c . '>';
}
$cs = implode('|',$ca);
}
else {
$cs = '<<>>'; // should be impossible to match
}
if (is_array($sec['allow_gid']) && count($sec['allow_gid'])) {
$ga = [];
foreach ($sec['allow_gid'] as $g) {
$ga[] = '<' . $g . '>';
}
$gs = implode('|',$ga);
}
else {
$gs = '<<>>'; // should be impossible to match
}
if(is_array($groups) && count($groups)) {
foreach($groups as $g)
$gs .= '|<' . $g . '>';
}
$sql = '';
if($observer_hash) {
$regexop = db_getfunc('REGEXP');
$sql = sprintf(
" OR (( NOT (deny_cid like '%s' OR deny_gid $regexop '%s')
AND ( allow_cid like '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0 ) )
))
" AND ( NOT (deny_cid $regexop '%s' OR deny_gid $regexop '%s')
AND ( allow_cid $regexop '%s' OR allow_gid $regexop '%s' OR ( allow_cid = '' AND allow_gid = '' AND item_private = 0) )
)
",
dbesc(protect_sprintf( '%<' . $observer_hash . '>%')),
dbesc($cs),
dbesc($gs),
dbesc(protect_sprintf( '%<' . $observer_hash . '>%')),
dbesc($cs),
dbesc($gs)
);
}
else {
$sql = EMPTY_STR;
}
return $sql;
}
@@ -510,7 +576,7 @@ function public_permissions_sql($observer_hash) {
* In this implementation, a security token is reusable (if the user submits a form, goes back and resubmits the form, maybe with small changes;
* or if the security token is used for ajax-calls that happen several times), but only valid for a certain amout of time (3hours).
* The "typename" seperates the security tokens of different types of forms. This could be relevant in the following case:
* A security token is used to protekt a link from CSRF (e.g. the "delete this profile"-link).
* A security token is used to protect a link from CSRF (e.g. the "delete this profile"-link).
* If the new page contains by any chance external elements, then the used security token is exposed by the referrer.
* Actually, important actions should not be triggered by Links / GET-Requests at all, but somethimes they still are,
* so this mechanism brings in some damage control (the attacker would be able to forge a request to a form of this type, but not to forms of other types).
@@ -564,24 +630,40 @@ function check_form_security_token_ForbiddenOnErr($typename = '', $formname = 'f
function init_groups_visitor($contact_id) {
$groups = [];
// private profiles are treated as a virtual group
$r = q("SELECT abook_profile from abook where abook_xchan = '%s' and abook_profile != '' ",
$x = q("select * from xchan where xchan_hash = '%s'",
dbesc($contact_id)
);
if($r) {
foreach($r as $rv) {
if (! $x) {
return $groups;
}
// include xchans for all zot-like networks
$xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ",
dbesc($contact_id),
dbesc($x[0]['xchan_guid']),
dbesc($x[0]['xchan_pubkey'])
);
if($xchans) {
$hashes = ids_to_querystr($xchans,'xchan_hash',true);
}
// private profiles are treated as a virtual group
$r = q("SELECT abook_profile from abook where abook_xchan in ( " . protect_sprintf($hashes) . " ) and abook_profile != '' ");
if ($r) {
foreach ($r as $rv) {
$groups[] = 'vp.' . $rv['abook_profile'];
}
}
// physical groups this channel is a member of
// physical groups this identity is a member of
$r = q("SELECT hash FROM pgrp left join pgrp_member on pgrp.id = pgrp_member.gid WHERE xchan = '%s' ",
dbesc($contact_id)
);
if($r) {
foreach($r as $rr)
$r = q("SELECT hash FROM pgrp left join pgrp_member on pgrp.id = pgrp_member.gid WHERE xchan in ( " . protect_sprintf($hashes) . " ) ");
if ($r) {
foreach ($r as $rr)
$groups[] = $rr['hash'];
}
return $groups;
@@ -589,6 +671,70 @@ function init_groups_visitor($contact_id) {
function get_security_ids($channel_id, $ob_hash) {
$ret = [
'channel_id' => [],
'allow_cid' => [],
'allow_gid' => []
];
if($channel_id) {
$ch = q("select channel_hash, channel_portable_id from channel where channel_id = %d",
intval($channel_id)
);
if($ch) {
$ret['channel_id'][] = $ch[0]['channel_hash'];
$ret['channel_id'][] = $ch[0]['channel_portable_id'];
}
}
$groups = [];
$x = q("select * from xchan where xchan_hash = '%s'",
dbesc($ob_hash)
);
if ($x) {
// include xchans for all zot-like networks
$xchans = q("select xchan_hash from xchan where xchan_hash = '%s' OR ( xchan_guid = '%s' AND xchan_pubkey = '%s' ) ",
dbesc($ob_hash),
dbesc($x[0]['xchan_guid']),
dbesc($x[0]['xchan_pubkey'])
);
if ($xchans) {
$ret['allow_cid'] = ids_to_array($xchans,'xchan_hash');
$hashes = ids_to_querystr($xchans,'xchan_hash',true);
// private profiles are treated as a virtual group
$r = q("SELECT abook_profile from abook where abook_xchan in ( " . protect_sprintf($hashes) . " ) and abook_profile != '' ");
if($r) {
foreach ($r as $rv) {
$groups[] = 'vp.' . $rv['abook_profile'];
}
}
// physical groups this identity is a member of
$r = q("SELECT hash FROM pgrp left join pgrp_member on pgrp.id = pgrp_member.gid WHERE xchan in ( " . protect_sprintf($hashes) . " ) ");
if($r) {
foreach ($r as $rv) {
$groups[] = $rv['hash'];
}
}
$ret['allow_gid'] = $groups;
}
}
return $ret;
}
// This is used to determine which uid have posts which are visible to the logged in user (from the API) for the
// public_timeline, and we can use this in a community page by making
// $perms = (PERMS_NETWORK|PERMS_PUBLIC) unless logged in.
-2
View File
@@ -543,8 +543,6 @@ function article_catblock($uid,$count = 0,$authors = '',$owner = '', $flags = 0,
function dir_tagblock($link,$r) {
$o = '';
$observer = get_observer_hash();
if(! $r)
$r = App::$data['directory_keywords'];
+1 -16
View File
@@ -20,7 +20,7 @@ define('RANDOM_STRING_TEXT', 0x01 );
/**
* @brief This is our template processor.
*
* @param string|SmartyEngine $s the string requiring macro substitution,
* @param string SmartyEngine $s the string requiring macro substitution,
* or an instance of SmartyEngine
* @param array $r key value pairs (search => replace)
*
@@ -2558,15 +2558,6 @@ function design_tools() {
*/
function website_portation_tools() {
$channel = App::get_channel();
$sys = false;
if(App::$is_sys && is_site_admin()) {
require_once('include/channel.php');
$channel = get_sys_channel();
$sys = true;
}
return replace_macros(get_markup_template('website_portation_tools.tpl'), [
'$title' => t('Import'),
'$import_label' => t('Import website...'),
@@ -2734,7 +2725,6 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
$name = substr($tag,(($exclusive) ? 2 : 1));
$newname = $name; // make a copy that we can mess with
$tagcid = 0;
$r = null;
@@ -2793,14 +2783,9 @@ function handle_tag(&$body, &$str_tags, $profile_uid, $tag, $in_network = true)
}
$fn_results = [];
$access_tag = EMPTY_STR;
// $r is set if we found something
if($r) {
+1
View File
@@ -1,6 +1,7 @@
<?php
use Zotlabs\Zot6\HTTPSig;
use Zotlabs\Lib\Libzot;
function xchan_store_lowlevel($arr) {
+48
View File
@@ -352,3 +352,51 @@ function owt_init($token) {
logger('OpenWebAuth: auth success from ' . $hubloc['xchan_addr']);
}
function observer_auth($ob_hash) {
if($ob_hash === false) {
return;
}
$r = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash
where hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s' order by hubloc_id desc",
dbesc($ob_hash),
dbesc($ob_hash),
dbesc($ob_hash)
);
if(! $r) {
// finger them if they can't be found.
$wf = discover_by_webbie($ob_hash);
if($wf) {
$r = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash
where hubloc_addr = '%s' or hubloc_id_url = '%s' or hubloc_hash = '%s' order by hubloc_id desc",
dbesc($ob_hash),
dbesc($ob_hash),
dbesc($ob_hash)
);
}
}
if(! $r) {
logger('unable to finger ' . $ob_hash);
return;
}
$hubloc = $r[0];
$_SESSION['authenticated'] = 1;
// normal visitor (remote_channel) login session credentials
$_SESSION['visitor_id'] = $hubloc['xchan_hash'];
$_SESSION['my_url'] = $hubloc['xchan_url'];
$_SESSION['my_address'] = $hubloc['hubloc_addr'];
$_SESSION['remote_hub'] = $hubloc['hubloc_url'];
$_SESSION['DNT'] = 1;
\App::set_observer($hubloc);
require_once('include/security.php');
\App::set_groups(init_groups_visitor($_SESSION['visitor_id']));
}
+6 -2
View File
@@ -1712,13 +1712,17 @@ function allowed_public_recips($msg) {
$condensed_recips[] = $rr['hash'];
$results = array();
$r = q("select channel_hash as hash from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and channel_removed = 0 ",
$r = q("select channel_hash as hash, channel_id from channel left join abook on abook_channel = channel_id where abook_xchan = '%s' and channel_removed = 0 ",
dbesc($hash)
);
if($r) {
foreach($r as $rr)
foreach($r as $rr) {
$cfg = get_abconfig($rr['channel_id'],$rr['hash'],'their_perms','view_stream');
if((! $cfg) && $scope !== 'any connections')
continue;
if(in_array($rr['hash'],$condensed_recips))
$results[] = array('hash' => $rr['hash']);
}
}
return $results;
}