aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs/Lib
diff options
context:
space:
mode:
Diffstat (limited to 'Zotlabs/Lib')
-rw-r--r--Zotlabs/Lib/Activity.php245
-rw-r--r--Zotlabs/Lib/Apps.php42
-rw-r--r--Zotlabs/Lib/Connect.php6
-rw-r--r--Zotlabs/Lib/Crypto.php206
-rw-r--r--Zotlabs/Lib/JSalmon.php4
-rw-r--r--Zotlabs/Lib/Keyutils.php99
-rw-r--r--Zotlabs/Lib/LDSignatures.php12
-rw-r--r--Zotlabs/Lib/Libsync.php2
-rw-r--r--Zotlabs/Lib/Libzot.php29
-rw-r--r--Zotlabs/Lib/PConfig.php1
-rw-r--r--Zotlabs/Lib/Queue.php4
-rw-r--r--Zotlabs/Lib/ThreadItem.php2
-rw-r--r--Zotlabs/Lib/Zotfinger.php12
13 files changed, 529 insertions, 135 deletions
diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php
index cedc9adc8..882bf4a1c 100644
--- a/Zotlabs/Lib/Activity.php
+++ b/Zotlabs/Lib/Activity.php
@@ -102,6 +102,20 @@ class Activity {
}
if ($x['success']) {
+ $m = parse_url($url);
+ if ($m) {
+ $y = [ 'scheme' => $m['scheme'], 'host' => $m['host'] ];
+ if (array_key_exists('port', $m))
+ $y['port'] = $m['port'];
+ $site_url = unparse_url($y);
+ q("UPDATE site SET site_update = '%s', site_dead = 0 WHERE site_url = '%s' AND site_update < %s - INTERVAL %s",
+ dbesc(datetime_convert()),
+ dbesc($site_url),
+ db_utcnow(),
+ db_quoteinterval('1 DAY')
+ );
+ }
+
$y = json_decode($x['body'], true);
logger('returned: ' . json_encode($y, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOGGER_DEBUG);
return json_decode($x['body'], true);
@@ -275,17 +289,27 @@ class Activity {
$numpages = $total / App::$pager['itemspage'];
$lastpage = (($numpages > intval($numpages)) ? intval($numpages) + 1 : $numpages);
+ $url_parts = parse_url($id);
+
+ $ret['partOf'] = z_root() . '/' . $url_parts['path'];
- $stripped = preg_replace('/([&|\?]page=[0-9]*)/', '', $id);
- $stripped = rtrim($stripped, '/');
+ $extra_query_args = '';
+ $query_args = null;
+ if(isset($url_parts['query'])) {
+ parse_str($url_parts['query'], $query_args);
+ }
- $ret['partOf'] = z_root() . '/' . $stripped;
+ if(is_array($query_args)) {
+ unset($query_args['page']);
+ foreach($query_args as $k => $v)
+ $extra_query_args .= '&' . urlencode($k) . '=' . urlencode($v);
+ }
if (App::$pager['page'] < $lastpage) {
- $ret['next'] = z_root() . '/' . $stripped . '?page=' . (intval(App::$pager['page']) + 1);
+ $ret['next'] = z_root() . '/' . $url_parts['path'] . '?page=' . (intval(App::$pager['page']) + 1) . $extra_query_args;
}
if (App::$pager['page'] > 1) {
- $ret['prev'] = z_root() . '/' . $stripped . '?page=' . (intval(App::$pager['page']) - 1);
+ $ret['prev'] = z_root() . '/' . $url_parts['path'] . '?page=' . (intval(App::$pager['page']) - 1) . $extra_query_args;
}
}
else {
@@ -355,6 +379,8 @@ class Activity {
$ret = [];
+
+
if ($i['verb'] === ACTIVITY_FRIEND) {
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
$objtype = 'Note';
@@ -413,7 +439,7 @@ class Activity {
$ret['published'] = datetime_convert('UTC', 'UTC', $i['created'], ATOM_TIME);
if ($i['created'] !== $i['edited'])
$ret['updated'] = datetime_convert('UTC', 'UTC', $i['edited'], ATOM_TIME);
- if ($i['expires'] <= NULL_DATE) {
+ if ($i['expires'] > NULL_DATE) {
$ret['expires'] = datetime_convert('UTC', 'UTC', $i['expires'], ATOM_TIME);
}
@@ -440,7 +466,7 @@ class Activity {
$ret['directMessage'] = true;
}
- if (array_key_exists('comments_closed', $i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] !== NULL_DATE) {
+ if (array_key_exists('comments_closed', $i) && $i['comments_closed'] !== EMPTY_STR && $i['comments_closed'] > NULL_DATE) {
if ($ret['commentPolicy']) {
$ret['commentPolicy'] .= ' ';
}
@@ -549,7 +575,7 @@ class Activity {
$ret = [];
- if ($item['tag'] && is_array($item['tag'])) {
+ if (array_key_exists('tag', $item) && is_array($item['tag'])) {
$ptr = $item['tag'];
if (!array_key_exists(0, $ptr)) {
$ptr = [$ptr];
@@ -558,23 +584,25 @@ class Activity {
if (!array_key_exists('type', $t))
$t['type'] = 'Hashtag';
- switch ($t['type']) {
- case 'Hashtag':
- $ret[] = ['ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name'])];
- break;
+ if (array_key_exists('href', $t) && array_key_exists('name', $t)) {
+ switch ($t['type']) {
+ case 'Hashtag':
+ $ret[] = ['ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name'])];
+ break;
- case 'Mention':
- $mention_type = substr($t['name'], 0, 1);
- if ($mention_type === '!') {
- $ret[] = ['ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'], 1))];
- }
- else {
- $ret[] = ['ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '@') ? substr($t['name'], 1) : $t['name'])];
- }
- break;
+ case 'Mention':
+ $mention_type = substr($t['name'], 0, 1);
+ if ($mention_type === '!') {
+ $ret[] = ['ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'], 1))];
+ }
+ else {
+ $ret[] = ['ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '@') ? substr($t['name'], 1) : $t['name'])];
+ }
+ break;
- default:
- break;
+ default:
+ break;
+ }
}
}
}
@@ -586,7 +614,7 @@ class Activity {
$ret = [];
- if ($item['term']) {
+ if (array_key_exists('term', $item) && is_array($item['term'])) {
foreach ($item['term'] as $t) {
switch ($t['ttype']) {
case TERM_HASHTAG:
@@ -617,7 +645,7 @@ class Activity {
$ret = [];
- if ($item['attach']) {
+ if (array_key_exists('attach', $item)) {
$atts = ((is_array($item['attach'])) ? $item['attach'] : json_decode($item['attach'], true));
if ($atts) {
foreach ($atts as $att) {
@@ -630,7 +658,7 @@ class Activity {
}
}
}
- if ($item['iconfig']) {
+ if (array_key_exists('iconfig', $item) && is_array($item['iconfig'])) {
foreach ($item['iconfig'] as $att) {
if ($att['sharing']) {
$value = ((is_string($att['v']) && preg_match('|^a:[0-9]+:{.*}$|s', $att['v'])) ? unserialize($att['v']) : $att['v']);
@@ -674,16 +702,16 @@ class Activity {
$ret = [];
- if ($item['attachment']) {
+ if (array_key_exists('attachment', $item) && is_array($item['attachment'])) {
foreach ($item['attachment'] as $att) {
$entry = [];
- if ($att['href'])
+ if (array_key_exists('href', $att))
$entry['href'] = $att['href'];
- elseif ($att['url'])
+ elseif (array_key_exists('url', $att))
$entry['href'] = $att['url'];
- if ($att['mediaType'])
+ if (array_key_exists('mediaType', $att))
$entry['type'] = $att['mediaType'];
- elseif ($att['type'] === 'Image')
+ elseif (array_key_exists('type', $att) && $att['type'] === 'Image')
$entry['type'] = 'image/jpeg';
if ($entry)
$ret[] = $entry;
@@ -698,7 +726,6 @@ class Activity {
$ret = [];
$reply = false;
-
if ($i['verb'] === ACTIVITY_FRIEND) {
// Hubzilla 'make-friend' activity, no direct mapping from AS1 to AS2 - make it a note
$ret['obj'] = [];
@@ -956,19 +983,17 @@ class Activity {
// Returns an array of URLS for any mention tags found in the item array $i.
static function map_mentions($i) {
- if (!$i['term']) {
- return [];
- }
-
$list = [];
- foreach ($i['term'] as $t) {
- if (!$t['url']) {
- continue;
- }
- if ($t['ttype'] == TERM_MENTION) {
- $url = self::lookup_term_url($t['url']);
- $list[] = (($url) ? $url : $t['url']);
+ if (array_key_exists('term', $i) && is_array($i['term'])) {
+ foreach ($i['term'] as $t) {
+ if (!$t['url']) {
+ continue;
+ }
+ if ($t['ttype'] == TERM_MENTION) {
+ $url = self::lookup_term_url($t['url']);
+ $list[] = (($url) ? $url : $t['url']);
+ }
}
}
@@ -1099,6 +1124,34 @@ class Activity {
return $ret;
}
+ static function encode_item_object($item, $elm = 'obj') {
+ $ret = [];
+
+ if ($item[$elm]) {
+ if (! is_array($item[$elm])) {
+ $item[$elm] = json_decode($item[$elm],true);
+ }
+ if ($item[$elm]['type'] === ACTIVITY_OBJ_PHOTO) {
+ $item[$elm]['id'] = $item['mid'];
+ }
+
+ $obj = self::encode_object($item[$elm]);
+ if ($obj)
+ return $obj;
+ else
+ return [];
+ }
+ else {
+ $obj = self::encode_item($item);
+ if ($obj)
+ return $obj;
+ else
+ return [];
+ }
+
+ }
+
+
static function activity_mapper($verb) {
if (strpos($verb, '/') === false) {
@@ -1115,6 +1168,7 @@ class Activity {
'http://activitystrea.ms/schema/1.0/tag' => 'Add',
'http://activitystrea.ms/schema/1.0/follow' => 'Follow',
'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow',
+ 'http://activitystrea.ms/schema/1.0/stop-following' => 'Unfollow',
'http://purl.org/zot/activity/attendyes' => 'Accept',
'http://purl.org/zot/activity/attendno' => 'Reject',
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept',
@@ -1162,6 +1216,7 @@ class Activity {
'http://activitystrea.ms/schema/1.0/tag' => 'Add',
'http://activitystrea.ms/schema/1.0/follow' => 'Follow',
'http://activitystrea.ms/schema/1.0/unfollow' => 'Unfollow',
+ 'http://activitystrea.ms/schema/1.0/stop-following' => 'Unfollow',
'http://purl.org/zot/activity/attendyes' => 'Accept',
'http://purl.org/zot/activity/attendno' => 'Reject',
'http://purl.org/zot/activity/attendmaybe' => 'TentativeAccept',
@@ -1340,7 +1395,7 @@ class Activity {
$abook_instance .= ',';
$abook_instance .= z_root();
- q("update abook set abook_instance = '%s', abook_not_here = 0
+ q("update abook set abook_instance = '%s', abook_not_here = 0
where abook_id = %d and abook_channel = %d",
dbesc($abook_instance),
intval($contact['abook_id']),
@@ -1552,13 +1607,13 @@ class Activity {
if ($inbox) {
$collections['inbox'] = $inbox;
- if ($person_obj['outbox'])
+ if (array_key_exists('outbox', $person_obj))
$collections['outbox'] = $person_obj['outbox'];
- if ($person_obj['followers'])
+ if (array_key_exists('followers', $person_obj))
$collections['followers'] = $person_obj['followers'];
- if ($person_obj['following'])
+ if (array_key_exists('following', $person_obj))
$collections['following'] = $person_obj['following'];
- if ($person_obj['endpoints'] && $person_obj['endpoints']['sharedInbox'])
+ if (array_key_exists('endpoints', $person_obj) && array_key_exists('sharedInbox', $person_obj['endpoints']))
$collections['sharedInbox'] = $person_obj['endpoints']['sharedInbox'];
}
@@ -1566,7 +1621,7 @@ class Activity {
if ($person_obj['id'] === $person_obj['publicKey']['owner']) {
$pubkey = $person_obj['publicKey']['publicKeyPem'];
if (strstr($pubkey, 'RSA ')) {
- $pubkey = rsatopem($pubkey);
+ $pubkey = Keyutils::rsaToPem($pubkey);
}
}
}
@@ -1620,7 +1675,7 @@ class Activity {
$m = parse_url($url);
if ($m) {
$hostname = $m['host'];
- $baseurl = $m['scheme'] . '://' . $m['host'] . (($m['port']) ? ':' . $m['port'] : '');
+ $site_url = $m['scheme'] . '://' . $m['host'] . (($m['port']) ? ':' . $m['port'] : '');
}
if (!$r) {
@@ -1630,7 +1685,7 @@ class Activity {
'hubloc_hash' => $url,
'hubloc_addr' => '',
'hubloc_network' => 'activitypub',
- 'hubloc_url' => $baseurl,
+ 'hubloc_url' => $site_url,
'hubloc_host' => $hostname,
'hubloc_callback' => $inbox,
'hubloc_updated' => datetime_convert(),
@@ -1640,6 +1695,13 @@ class Activity {
);
}
+ q("UPDATE site SET site_update = '%s', site_dead = 0 WHERE site_url = '%s' AND site_update < %s - INTERVAL %s",
+ dbesc(datetime_convert()),
+ dbesc($site_url),
+ db_utcnow(),
+ db_quoteinterval('1 DAY')
+ );
+
if (!$icon)
$icon = z_root() . '/' . get_default_profile_photo(300);
@@ -2037,6 +2099,15 @@ class Activity {
static function decode_note($act) {
+ // Within our family of projects, Follow/Unfollow of a thread is an internal activity which should not be transmitted,
+ // hence if we receive it - ignore or reject it.
+ // Unfollow is not defined by ActivityStreams, which prefers Undo->Follow.
+ // This may have to be revisited if AP projects start using Follow for objects other than actors.
+
+ if (in_array($act->type, [ 'Follow', 'Unfollow' ])) {
+ return false;
+ }
+
$response_activity = false;
$s = [];
@@ -2055,22 +2126,22 @@ class Activity {
$s['uuid'] = $act->obj['diaspora:guid'];
$s['parent_mid'] = $act->parent_id;
- if ($act->data['published']) {
+ if (array_key_exists('published', $act->data)) {
$s['created'] = datetime_convert('UTC', 'UTC', $act->data['published']);
}
- elseif ($act->obj['published']) {
+ elseif (array_key_exists('published', $act->obj)) {
$s['created'] = datetime_convert('UTC', 'UTC', $act->obj['published']);
}
- if ($act->data['updated']) {
+ if (array_key_exists('updated', $act->data)) {
$s['edited'] = datetime_convert('UTC', 'UTC', $act->data['updated']);
}
- elseif ($act->obj['updated']) {
+ elseif (array_key_exists('updated', $act->obj)) {
$s['edited'] = datetime_convert('UTC', 'UTC', $act->obj['updated']);
}
- if ($act->data['expires']) {
+ if (array_key_exists('expires', $act->data)) {
$s['expires'] = datetime_convert('UTC', 'UTC', $act->data['expires']);
}
- elseif ($act->obj['expires']) {
+ elseif (array_key_exists('expires', $act->obj)) {
$s['expires'] = datetime_convert('UTC', 'UTC', $act->obj['expires']);
}
@@ -2094,6 +2165,7 @@ class Activity {
$obj_actor = ((isset($act->obj['actor'])) ? $act->obj['actor'] : $act->get_actor('attributedTo', $act->obj));
// ensure we store the original actor
+
self::actor_store($obj_actor['id'], $obj_actor);
$mention = self::get_actor_bbmention($obj_actor['id']);
@@ -2129,10 +2201,10 @@ class Activity {
}
}
- if (!$s['created'])
+ if (! array_key_exists('created', $s))
$s['created'] = datetime_convert();
- if (!$s['edited'])
+ if (! array_key_exists('edited', $s))
$s['edited'] = $s['created'];
$s['title'] = (($response_activity) ? EMPTY_STR : self::bb_content($content, 'name'));
@@ -2233,17 +2305,20 @@ class Activity {
$s['iconfig'] = $a;
}
- if ($act->obj['type'] === 'Note' && $s['attach']) {
- $s['body'] .= self::bb_attach($s['attach'], $s['body']);
- }
+ if (array_key_exists('type', $act->obj)) {
- if ($act->obj['type'] === 'Question' && in_array($act->type, ['Create', 'Update'])) {
- if ($act->obj['endTime']) {
- $s['comments_closed'] = datetime_convert('UTC', 'UTC', $act->obj['endTime']);
+ if ($act->obj['type'] === 'Note' && $s['attach']) {
+ $s['body'] .= self::bb_attach($s['attach'], $s['body']);
+ }
+
+ if ($act->obj['type'] === 'Question' && in_array($act->type, ['Create', 'Update'])) {
+ if (array_key_exists('endTime', $act->obj)) {
+ $s['comments_closed'] = datetime_convert('UTC', 'UTC', $act->obj['endTime']);
+ }
}
}
- if ($act->obj['closed']) {
+ if (array_key_exists('closed', $act->obj)) {
$s['comments_closed'] = datetime_convert('UTC', 'UTC', $act->obj['closed']);
}
@@ -2659,7 +2734,7 @@ class Activity {
}
}
- if ($act->obj['conversation']) {
+ if (array_key_exists('conversation', $act->obj)) {
set_iconfig($item, 'ostatus', 'conversation', $act->obj['conversation'], 1);
}
@@ -2817,9 +2892,6 @@ class Activity {
logger('not a valid activity');
break;
}
- if (is_array($a->actor) && array_key_exists('id', $a->actor)) {
- Activity::actor_store($a->actor['id'], $a->actor);
- }
$item = Activity::decode_note($a);
@@ -3277,17 +3349,17 @@ class Activity {
$ret = false;
foreach ($attach as $a) {
- if (strpos($a['type'], 'image') !== false) {
+ if (array_key_exists('type',$a) && stripos($a['type'], 'image') !== false) {
if (self::media_not_in_body($a['href'], $body)) {
$ret .= "\n\n" . '[img]' . $a['href'] . '[/img]';
}
}
- if (array_key_exists('type', $a) && strpos($a['type'], 'video') === 0) {
+ if (array_key_exists('type', $a) && stripos($a['type'], 'video') !== false) {
if (self::media_not_in_body($a['href'], $body)) {
$ret .= "\n\n" . '[video]' . $a['href'] . '[/video]';
}
}
- if (array_key_exists('type', $a) && strpos($a['type'], 'audio') === 0) {
+ if (array_key_exists('type', $a) && stripos($a['type'], 'audio') !== false) {
if (self::media_not_in_body($a['href'], $body)) {
$ret .= "\n\n" . '[audio]' . $a['href'] . '[/audio]';
}
@@ -3315,22 +3387,25 @@ class Activity {
require_once('include/event.php');
$ret = false;
- if (is_array($content[$field])) {
- foreach ($content[$field] as $k => $v) {
- $ret .= html2bbcode($v);
- // save this for auto-translate or dynamic filtering
- // $ret .= '[language=' . $k . ']' . html2bbcode($v) . '[/language]';
- }
- }
- else {
- if ($field === 'bbcode' && array_key_exists('bbcode', $content)) {
- $ret = $content[$field];
+ if (array_key_exists($field, $content)) {
+ if (is_array($content[$field])) {
+ foreach ($content[$field] as $k => $v) {
+ $ret .= html2bbcode($v);
+ // save this for auto-translate or dynamic filtering
+ // $ret .= '[language=' . $k . ']' . html2bbcode($v) . '[/language]';
+ }
}
else {
- $ret = html2bbcode($content[$field]);
+ if ($field === 'bbcode' && array_key_exists('bbcode', $content)) {
+ $ret = $content[$field];
+ }
+ else {
+ $ret = html2bbcode($content[$field]);
+ }
}
}
- if ($field === 'content' && $content['event'] && (!strpos($ret, '[event'))) {
+
+ if ($field === 'content' && array_key_exists('event', $content) && (!strpos($ret, '[event'))) {
$ret .= format_event_bbcode($content['event']);
}
diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php
index d77a3fda2..5ef4ecc8d 100644
--- a/Zotlabs/Lib/Apps.php
+++ b/Zotlabs/Lib/Apps.php
@@ -551,7 +551,7 @@ class Apps {
'$app' => $papp,
'$icon' => $icon,
'$hosturl' => $hosturl,
- '$purchase' => (($papp['page'] && (! $installed)) ? t('Purchase') : ''),
+ '$purchase' => ((isset($papp['page']) && (! $installed)) ? t('Purchase') : ''),
'$installed' => $installed,
'$action_label' => (($hosturl && in_array($mode, ['view','install'])) ? $install_action : ''),
'$edit' => ((local_channel() && $installed && $mode == 'edit') ? t('Edit') : ''),
@@ -559,8 +559,8 @@ class Apps {
'$undelete' => ((local_channel() && $mode == 'edit') ? t('Undelete') : ''),
'$settings_url' => ((local_channel() && $installed && $mode == 'list') ? $papp['settings_url'] : ''),
'$deleted' => $papp['deleted'],
- '$feature' => (($papp['embed'] || $mode == 'edit') ? false : true),
- '$pin' => (($papp['embed'] || $mode == 'edit') ? false : true),
+ '$feature' => ((isset($papp['embed']) || $mode == 'edit') ? false : true),
+ '$pin' => ((isset($papp['embed']) || $mode == 'edit') ? false : true),
'$featured' => ((strpos($papp['categories'], 'nav_featured_app') === false) ? false : true),
'$pinned' => ((strpos($papp['categories'], 'nav_pinned_app') === false) ? false : true),
'$navapps' => (($mode == 'nav') ? true : false),
@@ -1276,58 +1276,58 @@ class Apps {
$ret['type'] = 'personal';
- if($app['app_id'])
+ if(!empty($app['app_id']))
$ret['guid'] = $app['app_id'];
- if($app['app_sig'])
+ if(!empty($app['app_sig']))
$ret['sig'] = $app['app_sig'];
- if($app['app_author'])
+ if(!empty($app['app_author']))
$ret['author'] = $app['app_author'];
- if($app['app_name'])
+ if(!empty($app['app_name']))
$ret['name'] = $app['app_name'];
- if($app['app_desc'])
+ if(!empty($app['app_desc']))
$ret['desc'] = $app['app_desc'];
- if($app['app_url'])
+ if(!empty($app['app_url']))
$ret['url'] = $app['app_url'];
- if($app['app_photo'])
+ if(!empty($app['app_photo']))
$ret['photo'] = $app['app_photo'];
- if($app['app_icon'])
+ if(!empty($app['app_icon']))
$ret['icon'] = $app['app_icon'];
- if($app['app_version'])
+ if(!empty($app['app_version']))
$ret['version'] = $app['app_version'];
- if($app['app_addr'])
+ if(!empty($app['app_addr']))
$ret['addr'] = $app['app_addr'];
- if($app['app_price'])
+ if(!empty($app['app_price']))
$ret['price'] = $app['app_price'];
- if($app['app_page'])
+ if(!empty($app['app_page']))
$ret['page'] = $app['app_page'];
- if($app['app_requires'])
+ if(!empty($app['app_requires']))
$ret['requires'] = $app['app_requires'];
- if($app['app_system'])
+ if(!empty($app['app_system']))
$ret['system'] = $app['app_system'];
- if($app['app_options'])
+ if(!empty($app['app_options']))
$ret['options'] = $app['app_options'];
- if($app['app_plugin'])
+ if(!empty($app['app_plugin']))
$ret['plugin'] = trim($app['app_plugin']);
- if($app['app_deleted'])
+ if(!empty($app['app_deleted']))
$ret['deleted'] = $app['app_deleted'];
- if($app['term']) {
+ if(!empty($app['term']) && is_array($app['term'])) {
$s = '';
foreach($app['term'] as $t) {
if($s)
diff --git a/Zotlabs/Lib/Connect.php b/Zotlabs/Lib/Connect.php
index 481b02ce2..21bec171b 100644
--- a/Zotlabs/Lib/Connect.php
+++ b/Zotlabs/Lib/Connect.php
@@ -207,13 +207,13 @@ class Connect {
}
$my_perms = $p['perms'];
-
+
$profile_assign = get_pconfig($uid,'system','profile_assign','');
// See if we are already connected by virtue of having an abook record
- $r = q("select abook_id, abook_xchan, abook_pending, abook_instance from abook
+ $r = q("select abook_id, abook_xchan, abook_pending, abook_instance from abook
where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($xchan_hash),
intval($uid)
@@ -282,7 +282,7 @@ class Connect {
// fetch the entire record
- $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash
+ $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash
where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($xchan_hash),
intval($uid)
diff --git a/Zotlabs/Lib/Crypto.php b/Zotlabs/Lib/Crypto.php
new file mode 100644
index 000000000..f1794ae64
--- /dev/null
+++ b/Zotlabs/Lib/Crypto.php
@@ -0,0 +1,206 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+use Exception;
+
+class Crypto {
+
+ public static $openssl_algorithms = [
+
+ // zot6 nickname, opensslname, keylength, ivlength
+
+ ['aes256ctr', 'aes-256-ctr', 32, 16],
+ ['camellia256cfb', 'camellia-256-cfb', 32, 16],
+ ['cast5cfb', 'cast5-cfb', 16, 8],
+ ['aes256cbc', 'aes-256-cbc', 32, 16] // remove after legacy zot has been sunset
+
+ ];
+
+ public static function methods() {
+ $ret = [];
+
+ foreach (self::$openssl_algorithms as $ossl) {
+ $ret[] = $ossl[0] . '.oaep';
+ }
+
+ call_hooks('crypto_methods', $ret);
+ return $ret;
+ }
+
+ public static function signing_methods() {
+
+ $ret = ['sha256'];
+ call_hooks('signing_methods', $ret);
+ return $ret;
+
+ }
+
+ public static function new_keypair($bits) {
+
+ $openssl_options = [
+ 'digest_alg' => 'sha1',
+ 'private_key_bits' => $bits,
+ 'encrypt_key' => false
+ ];
+
+ $conf = get_config('system', 'openssl_conf_file');
+
+ if ($conf) {
+ $openssl_options['config'] = $conf;
+ }
+
+ $result = openssl_pkey_new($openssl_options);
+
+ if (empty($result)) {
+ return false;
+ }
+
+ // Get private key
+
+ $response = ['prvkey' => '', 'pubkey' => ''];
+
+ openssl_pkey_export($result, $response['prvkey']);
+
+ // Get public key
+ $pkey = openssl_pkey_get_details($result);
+ $response['pubkey'] = $pkey["key"];
+
+ return $response;
+
+ }
+
+ public static function sign($data, $key, $alg = 'sha256') {
+
+ if (!$key) {
+ return false;
+ }
+
+ $sig = '';
+ openssl_sign($data, $sig, $key, $alg);
+ return $sig;
+ }
+
+ public static function verify($data, $sig, $key, $alg = 'sha256') {
+
+ if (!$key) {
+ return false;
+ }
+
+ try {
+ $verify = openssl_verify($data, $sig, $key, $alg);
+ } catch (Exception $e) {
+ $verify = (-1);
+ }
+
+ if ($verify === (-1)) {
+ while ($msg = openssl_error_string()) {
+ logger('openssl_verify: ' . $msg, LOGGER_NORMAL, LOG_ERR);
+ }
+ btlogger('openssl_verify: key: ' . $key, LOGGER_DEBUG, LOG_ERR);
+ }
+
+ return (($verify > 0) ? true : false);
+ }
+
+ public static function encapsulate($data, $pubkey, $alg) {
+
+ if (!($alg && $pubkey)) {
+ return $data;
+ }
+
+ $alg_base = $alg;
+ $padding = OPENSSL_PKCS1_PADDING;
+
+ $exts = explode('.', $alg);
+ if (count($exts) > 1) {
+ switch ($exts[1]) {
+ case 'oaep':
+ $padding = OPENSSL_PKCS1_OAEP_PADDING;
+ break;
+ default:
+ break;
+ }
+ $alg_base = $exts[0];
+ }
+
+ $method = null;
+
+ foreach (self::$openssl_algorithms as $ossl) {
+ if ($ossl[0] === $alg_base) {
+ $method = $ossl;
+ break;
+ }
+ }
+
+ if ($method) {
+ $result = ['encrypted' => true];
+
+ $key = openssl_random_pseudo_bytes(256);
+ $iv = openssl_random_pseudo_bytes(256);
+
+ $key1 = substr($key, 0, $method[2]);
+ $iv1 = substr($iv, 0, $method[3]);
+
+ $result['data'] = base64url_encode(openssl_encrypt($data, $method[1], $key1, OPENSSL_RAW_DATA, $iv1), true);
+
+ openssl_public_encrypt($key, $k, $pubkey, $padding);
+ openssl_public_encrypt($iv, $i, $pubkey, $padding);
+
+ $result['alg'] = $alg;
+ $result['key'] = base64url_encode($k, true);
+ $result['iv'] = base64url_encode($i, true);
+ return $result;
+
+ }
+ else {
+ $x = ['data' => $data, 'pubkey' => $pubkey, 'alg' => $alg, 'result' => $data];
+ call_hooks('crypto_encapsulate', $x);
+ return $x['result'];
+ }
+ }
+
+ public static function unencapsulate($data, $prvkey) {
+
+ if (!(is_array($data) && array_key_exists('encrypted', $data) && array_key_exists('alg', $data) && $data['alg'])) {
+ logger('not encrypted');
+
+ return $data;
+ }
+
+ $alg_base = $data['alg'];
+ $padding = OPENSSL_PKCS1_PADDING;
+
+ $exts = explode('.', $data['alg']);
+ if (count($exts) > 1) {
+ switch ($exts[1]) {
+ case 'oaep':
+ $padding = OPENSSL_PKCS1_OAEP_PADDING;
+ break;
+ default:
+ break;
+ }
+ $alg_base = $exts[0];
+ }
+
+ $method = null;
+
+ foreach (self::$openssl_algorithms as $ossl) {
+ if ($ossl[0] === $alg_base) {
+ $method = $ossl;
+ break;
+ }
+ }
+
+ if ($method) {
+ openssl_private_decrypt(base64url_decode($data['key']), $k, $prvkey, $padding);
+ openssl_private_decrypt(base64url_decode($data['iv']), $i, $prvkey, $padding);
+ return openssl_decrypt(base64url_decode($data['data']), $method[1], substr($k, 0, $method[2]), OPENSSL_RAW_DATA, substr($i, 0, $method[3]));
+ }
+ else {
+ $x = ['data' => $data, 'prvkey' => $prvkey, 'alg' => $data['alg'], 'result' => $data];
+ call_hooks('crypto_unencapsulate', $x);
+ return $x['result'];
+ }
+ }
+}
diff --git a/Zotlabs/Lib/JSalmon.php b/Zotlabs/Lib/JSalmon.php
index 7f63cf914..f9fe99706 100644
--- a/Zotlabs/Lib/JSalmon.php
+++ b/Zotlabs/Lib/JSalmon.php
@@ -18,7 +18,7 @@ class JSalmon {
$precomputed = '.' . base64url_encode($data_type,true) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng';
- $signature = base64url_encode(rsa_sign($data . $precomputed, $key), true);
+ $signature = base64url_encode(Crypto::sign($data . $precomputed, $key), true);
return ([
'signed' => true,
@@ -54,7 +54,7 @@ class JSalmon {
$key = HTTPSig::get_key(EMPTY_STR,'zot6',base64url_decode($x['sigs']['key_id']));
logger('key: ' . print_r($key,true));
if($key['portable_id'] && $key['public_key']) {
- if(rsa_verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) {
+ if(Crypto::verify($signed_data,base64url_decode($x['sigs']['value']),$key['public_key'])) {
logger('verified');
$ret = [ 'success' => true, 'signer' => $key['portable_id'], 'hubloc' => $key['hubloc'] ];
}
diff --git a/Zotlabs/Lib/Keyutils.php b/Zotlabs/Lib/Keyutils.php
new file mode 100644
index 000000000..616ecfcf6
--- /dev/null
+++ b/Zotlabs/Lib/Keyutils.php
@@ -0,0 +1,99 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+use phpseclib\Crypt\RSA;
+use phpseclib\Math\BigInteger;
+
+/**
+ * Keyutils
+ * Convert RSA keys between various formats
+ */
+class Keyutils {
+
+ /**
+ * @param string $m modulo
+ * @param string $e exponent
+ * @return string
+ */
+ public static function meToPem($m, $e) {
+
+ $rsa = new RSA();
+ $rsa->loadKey([
+ 'e' => new BigInteger($e, 256),
+ 'n' => new BigInteger($m, 256)
+ ]);
+ return $rsa->getPublicKey();
+
+ }
+
+ /**
+ * @param string key
+ * @return string
+ */
+ public static function rsaToPem($key) {
+
+ $rsa = new RSA();
+ $rsa->setPublicKey($key);
+
+ return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS8);
+
+ }
+
+ /**
+ * @param string key
+ * @return string
+ */
+ public static function pemToRsa($key) {
+
+ $rsa = new RSA();
+ $rsa->setPublicKey($key);
+
+ return $rsa->getPublicKey(RSA::PUBLIC_FORMAT_PKCS1);
+
+ }
+
+ /**
+ * @param string $key key
+ * @param string $m reference modulo
+ * @param string $e reference exponent
+ */
+ public static function pemToMe($key, &$m, &$e) {
+
+ $rsa = new RSA();
+ $rsa->loadKey($key);
+ $rsa->setPublicKey();
+
+ $m = $rsa->modulus->toBytes();
+ $e = $rsa->exponent->toBytes();
+
+ }
+
+ /**
+ * @param string $pubkey
+ * @return string
+ */
+ public static function salmonKey($pubkey) {
+ self::pemToMe($pubkey, $m, $e);
+ return 'RSA' . '.' . base64url_encode($m, true) . '.' . base64url_encode($e, true);
+ }
+
+ /**
+ * @param string $key
+ * @return string
+ */
+ public static function convertSalmonKey($key) {
+ if (strstr($key, ','))
+ $rawkey = substr($key, strpos($key, ',') + 1);
+ else
+ $rawkey = substr($key, 5);
+
+ $key_info = explode('.', $rawkey);
+
+ $m = base64url_decode($key_info[1]);
+ $e = base64url_decode($key_info[2]);
+
+ return self::meToPem($m, $e);
+ }
+
+} \ No newline at end of file
diff --git a/Zotlabs/Lib/LDSignatures.php b/Zotlabs/Lib/LDSignatures.php
index 2eba66ccf..1c2095f10 100644
--- a/Zotlabs/Lib/LDSignatures.php
+++ b/Zotlabs/Lib/LDSignatures.php
@@ -12,7 +12,7 @@ class LDSignatures {
$ohash = self::hash(self::signable_options($data['signature']));
$dhash = self::hash(self::signable_data($data));
- $x = rsa_verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey);
+ $x = Crypto::verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey);
logger('LD-verify: ' . intval($x));
return $x;
@@ -35,11 +35,11 @@ class LDSignatures {
$ohash = self::hash(self::signable_options($options));
$dhash = self::hash(self::signable_data($data));
- $options['signatureValue'] = base64_encode(rsa_sign($ohash . $dhash,$channel['channel_prvkey']));
+ $options['signatureValue'] = base64_encode(Crypto::sign($ohash . $dhash,$channel['channel_prvkey']));
$signed = array_merge([
- '@context' => [
- ACTIVITYSTREAMS_JSONLD_REV,
+ '@context' => [
+ ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1' ],
],$options);
@@ -88,7 +88,7 @@ class LDSignatures {
return '';
jsonld_set_document_loader('jsonld_document_loader');
-
+
try {
$d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
}
@@ -117,7 +117,7 @@ class LDSignatures {
$precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
- $signature = base64url_encode(rsa_sign($data . $precomputed,$channel['channel_prvkey']));
+ $signature = base64url_encode(Crypto::sign($data . $precomputed,$channel['channel_prvkey']));
return ([
'id' => $arr['id'],
diff --git a/Zotlabs/Lib/Libsync.php b/Zotlabs/Lib/Libsync.php
index e16b68cf8..7e97e4c70 100644
--- a/Zotlabs/Lib/Libsync.php
+++ b/Zotlabs/Lib/Libsync.php
@@ -781,7 +781,7 @@ class Libsync {
$t = datetime_convert('UTC', 'UTC', 'now - 15 minutes');
if (array_key_exists('site', $arr) && $location['url'] == $arr['site']['url']) {
- q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d and hubloc_connected < '%s'",
+ q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d and hubloc_updated < '%s'",
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($r[0]['hubloc_id']),
diff --git a/Zotlabs/Lib/Libzot.php b/Zotlabs/Lib/Libzot.php
index 0ead8402e..db35dfb70 100644
--- a/Zotlabs/Lib/Libzot.php
+++ b/Zotlabs/Lib/Libzot.php
@@ -130,7 +130,7 @@ class Libzot {
if ($remote_key) {
$algorithm = self::best_algorithm($methods);
if ($algorithm) {
- $data = crypto_encapsulate(json_encode($data), $remote_key, $algorithm);
+ $data = Crypto::encapsulate(json_encode($data), $remote_key, $algorithm);
}
}
@@ -143,7 +143,7 @@ class Libzot {
*
* @param string $methods
* Comma separated list of encryption methods
- * @return string first match from our site method preferences crypto_methods() array
+ * @return string first match from our site method preferences Crypto::methods() array
* of a method which is common to both sites; or 'aes256cbc' if no matches are found.
*/
static function best_algorithm($methods) {
@@ -167,7 +167,7 @@ class Libzot {
if ($methods) {
$x = explode(',', $methods);
if ($x) {
- $y = crypto_methods();
+ $y = Crypto::methods();
if ($y) {
foreach ($y as $yv) {
$yv = trim($yv);
@@ -299,7 +299,6 @@ class Libzot {
}
$record = Zotfinger::exec($url, $channel);
-
// Check the HTTP signature
$hsig = $record['signature'];
@@ -983,7 +982,7 @@ class Libzot {
logger('Headers: ' . print_r($arr['header'], true), LOGGER_DATA, LOG_DEBUG);
}
- $x = crypto_unencapsulate($x, get_config('system', 'prvkey'));
+ $x = Crypto::unencapsulate($x, get_config('system', 'prvkey'));
if (!is_array($x)) {
$x = json_decode($x, true);
@@ -1268,8 +1267,13 @@ class Libzot {
}
}
}
+
if ($AS->data['signed_data']) {
- IConfig::Set($arr, 'activitystreams', 'signed_data', $AS->data['signed_data'], false);
+ IConfig::Set($arr, 'activitypub', 'signed_data', $AS->data['signed_data'], false);
+ $j = json_decode($AS->data['signed_data'], true);
+ if ($j) {
+ IConfig::Set($arr, 'activitypub', 'rawmsg', json_encode(JSalmon::unpack($j['data'])), true);
+ }
}
logger('Activity received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG);
@@ -1953,7 +1957,11 @@ class Libzot {
}
if ($AS->data['signed_data']) {
- IConfig::Set($arr, 'activitystreams', 'signed_data', $AS->data['signed_data'], false);
+ IConfig::Set($arr, 'activitypub', 'signed_data', $AS->data['signed_data'], false);
+ $j = json_decode($AS->data['signed_data'], true);
+ if ($j) {
+ IConfig::Set($arr, 'activitypub', 'rawmsg', json_encode(JSalmon::unpack($j['data'])), true);
+ }
}
logger('FOF Activity received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG);
@@ -3020,7 +3028,7 @@ class Libzot {
$ret['site']['directory_url'] = z_root() . '/dirsearch';
- $ret['site']['encryption'] = crypto_methods();
+ $ret['site']['encryption'] = Crypto::methods();
$ret['site']['zot'] = System::get_zot_revision();
// hide detailed site information if you're off the grid
@@ -3140,6 +3148,11 @@ class Libzot {
);
}
+ // this site obviously isn't dead because they are trying to communicate with us.
+ q("update site set site_dead = 0 where site_dead = 1 and site_url = '%s' ",
+ dbesc($hub['hubloc_url'])
+ );
+
return $hub['hubloc_url'];
}
diff --git a/Zotlabs/Lib/PConfig.php b/Zotlabs/Lib/PConfig.php
index c08c11e75..765131f0d 100644
--- a/Zotlabs/Lib/PConfig.php
+++ b/Zotlabs/Lib/PConfig.php
@@ -132,6 +132,7 @@ class PConfig {
// manage array value
$dbvalue = ((is_array($value)) ? serialize($value) : $value);
$dbvalue = ((is_bool($dbvalue)) ? intval($dbvalue) : $dbvalue);
+ $new = false;
$now = datetime_convert();
if (! $updated) {
diff --git a/Zotlabs/Lib/Queue.php b/Zotlabs/Lib/Queue.php
index 779719d8b..373a7d304 100644
--- a/Zotlabs/Lib/Queue.php
+++ b/Zotlabs/Lib/Queue.php
@@ -116,7 +116,7 @@ class Queue {
dbesc(($arr['driver']) ? $arr['driver'] : 'zot6'),
dbesc($arr['posturl']),
intval(1),
- intval(($arr['priority']) ? $arr['priority'] : 0),
+ intval(isset($arr['priority']) ? $arr['priority'] : 0),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
@@ -134,7 +134,7 @@ class Queue {
$base = null;
$h = parse_url($outq['outq_posturl']);
if($h !== false)
- $base = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : '');
+ $base = $h['scheme'] . '://' . $h['host'] . (isset($h['port']) ? ':' . $h['port'] : '');
if(($base) && ($base !== z_root()) && ($immediate)) {
$y = q("select site_update, site_dead from site where site_url = '%s' ",
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php
index 2fb07c1cb..c0d5c001b 100644
--- a/Zotlabs/Lib/ThreadItem.php
+++ b/Zotlabs/Lib/ThreadItem.php
@@ -43,7 +43,7 @@ class ThreadItem {
$observer = \App::get_observer();
// Prepare the children
- if($data['children']) {
+ if(isset($data['children'])) {
foreach($data['children'] as $item) {
/*
diff --git a/Zotlabs/Lib/Zotfinger.php b/Zotlabs/Lib/Zotfinger.php
index faaf28f35..840d91403 100644
--- a/Zotlabs/Lib/Zotfinger.php
+++ b/Zotlabs/Lib/Zotfinger.php
@@ -18,8 +18,8 @@ class Zotfinger {
if($channel && $m) {
- $headers = [
- 'Accept' => 'application/x-zot+json',
+ $headers = [
+ 'Accept' => 'application/x-zot+json',
'Content-Type' => 'application/x-zot+json',
'X-Zot-Token' => random_string(),
'Digest' => HTTPSig::generate_digest_header($data),
@@ -29,9 +29,9 @@ class Zotfinger {
$h = HTTPSig::create_sig($headers,$channel['channel_prvkey'],channel_url($channel),false);
}
else {
- $h = [ 'Accept: application/x-zot+json' ];
+ $h = [ 'Accept: application/x-zot+json' ];
}
-
+
$result = [];
$redirects = 0;
@@ -43,11 +43,11 @@ class Zotfinger {
if ($verify) {
$result['signature'] = HTTPSig::verify($x, EMPTY_STR, 'zot6');
}
-
+
$result['data'] = json_decode($x['body'],true);
if($result['data'] && is_array($result['data']) && array_key_exists('encrypted',$result['data']) && $result['data']['encrypted']) {
- $result['data'] = json_decode(crypto_unencapsulate($result['data'],get_config('system','prvkey')),true);
+ $result['data'] = json_decode(Crypto::unencapsulate($result['data'],get_config('system','prvkey')),true);
}
logger('decrypted: ' . print_r($result,true));