aboutsummaryrefslogtreecommitdiffstats
path: root/Zotlabs
diff options
context:
space:
mode:
Diffstat (limited to 'Zotlabs')
-rw-r--r--Zotlabs/Daemon/Deliver.php3
-rw-r--r--Zotlabs/Daemon/Gprobe.php2
-rw-r--r--Zotlabs/Daemon/Importfile.php47
-rw-r--r--Zotlabs/Daemon/Notifier.php68
-rw-r--r--Zotlabs/Lib/ActivityStreams.php199
-rw-r--r--Zotlabs/Lib/ActivityStreams2.php86
-rw-r--r--Zotlabs/Lib/Apps.php41
-rw-r--r--Zotlabs/Lib/Enotify.php6
-rw-r--r--Zotlabs/Lib/JSalmon.php38
-rw-r--r--Zotlabs/Lib/LDSignatures.php135
-rw-r--r--Zotlabs/Lib/MarkdownSoap.php2
-rw-r--r--Zotlabs/Lib/NativeWiki.php84
-rw-r--r--Zotlabs/Lib/NativeWikiPage.php36
-rw-r--r--Zotlabs/Lib/PConfig.php9
-rw-r--r--Zotlabs/Lib/SConfig.php25
-rw-r--r--Zotlabs/Lib/System.php7
-rw-r--r--Zotlabs/Lib/ThreadItem.php32
-rw-r--r--Zotlabs/Lib/ThreadStream.php15
-rw-r--r--Zotlabs/Module/Acl.php57
-rw-r--r--Zotlabs/Module/Admin/Site.php5
-rw-r--r--Zotlabs/Module/Ap_probe.php38
-rw-r--r--Zotlabs/Module/Apporder.php43
-rw-r--r--Zotlabs/Module/Apps.php2
-rw-r--r--Zotlabs/Module/Attach.php2
-rw-r--r--Zotlabs/Module/Bookmarks.php2
-rw-r--r--Zotlabs/Module/Card_edit.php138
-rw-r--r--Zotlabs/Module/Cards.php187
-rw-r--r--Zotlabs/Module/Cdav.php82
-rw-r--r--Zotlabs/Module/Changeaddr.php88
-rw-r--r--Zotlabs/Module/Channel.php35
-rw-r--r--Zotlabs/Module/Chat.php2
-rw-r--r--Zotlabs/Module/Common.php31
-rw-r--r--Zotlabs/Module/Connections.php2
-rw-r--r--Zotlabs/Module/Connedit.php7
-rw-r--r--Zotlabs/Module/Dav.php74
-rw-r--r--Zotlabs/Module/Directory.php2
-rw-r--r--Zotlabs/Module/Display.php107
-rw-r--r--Zotlabs/Module/Events.php2
-rw-r--r--Zotlabs/Module/File_upload.php20
-rw-r--r--Zotlabs/Module/Filestorage.php16
-rw-r--r--Zotlabs/Module/Getfile.php2
-rw-r--r--Zotlabs/Module/Help.php7
-rw-r--r--Zotlabs/Module/Import.php39
-rw-r--r--Zotlabs/Module/Invite.php2
-rw-r--r--Zotlabs/Module/Item.php55
-rw-r--r--Zotlabs/Module/Lang.php2
-rw-r--r--Zotlabs/Module/Like.php2
-rw-r--r--Zotlabs/Module/Linkinfo.php2
-rw-r--r--Zotlabs/Module/Logout.php12
-rw-r--r--Zotlabs/Module/Magic.php31
-rw-r--r--Zotlabs/Module/Mail.php2
-rw-r--r--Zotlabs/Module/Manage.php2
-rw-r--r--Zotlabs/Module/Moderate.php24
-rw-r--r--Zotlabs/Module/Mood.php2
-rw-r--r--Zotlabs/Module/Network.php44
-rw-r--r--Zotlabs/Module/New_channel.php2
-rw-r--r--Zotlabs/Module/Notifications.php35
-rw-r--r--Zotlabs/Module/Notify.php16
-rw-r--r--Zotlabs/Module/Oep.php204
-rw-r--r--Zotlabs/Module/Ofeed.php2
-rw-r--r--Zotlabs/Module/Owa.php53
-rw-r--r--Zotlabs/Module/Pdledit.php26
-rw-r--r--Zotlabs/Module/Photos.php13
-rw-r--r--Zotlabs/Module/Ping.php205
-rw-r--r--Zotlabs/Module/Poke.php2
-rw-r--r--Zotlabs/Module/Post.php8
-rw-r--r--Zotlabs/Module/Probe.php2
-rw-r--r--Zotlabs/Module/Profile.php14
-rw-r--r--Zotlabs/Module/Profile_photo.php12
-rw-r--r--Zotlabs/Module/Pubsites.php7
-rw-r--r--Zotlabs/Module/Pubstream.php93
-rw-r--r--Zotlabs/Module/Register.php18
-rw-r--r--Zotlabs/Module/Rmagic.php8
-rw-r--r--Zotlabs/Module/Rpost.php84
-rw-r--r--Zotlabs/Module/Search.php2
-rw-r--r--Zotlabs/Module/Settings/Channel.php8
-rw-r--r--Zotlabs/Module/Suggest.php2
-rw-r--r--Zotlabs/Module/Tasks.php3
-rw-r--r--Zotlabs/Module/Thing.php4
-rw-r--r--Zotlabs/Module/Update_cards.php39
-rw-r--r--Zotlabs/Module/Wall_attach.php6
-rw-r--r--Zotlabs/Module/Webpages.php2
-rw-r--r--Zotlabs/Module/Wfinger.php50
-rw-r--r--Zotlabs/Module/Wiki.php135
-rw-r--r--Zotlabs/Module/Xrd.php1
-rw-r--r--Zotlabs/Module/Zfinger.php30
-rw-r--r--Zotlabs/Render/Comanche.php14
-rw-r--r--Zotlabs/Storage/Browser.php5
-rw-r--r--Zotlabs/Storage/File.php4
-rw-r--r--Zotlabs/Web/CheckJS.php6
-rw-r--r--Zotlabs/Web/HTTPHeaders.php14
-rw-r--r--Zotlabs/Web/HTTPSig.php313
-rw-r--r--Zotlabs/Web/Router.php13
-rw-r--r--Zotlabs/Web/WebServer.php44
-rw-r--r--Zotlabs/Widget/Categories.php15
-rw-r--r--Zotlabs/Widget/Common_friends.php19
-rw-r--r--Zotlabs/Widget/Helpindex.php14
-rw-r--r--Zotlabs/Widget/Notifications.php150
-rw-r--r--Zotlabs/Widget/Wiki_pages.php9
-rw-r--r--Zotlabs/Zot/Auth.php14
-rw-r--r--Zotlabs/Zot/Finger.php23
-rw-r--r--Zotlabs/Zot/IHandler.php2
-rw-r--r--Zotlabs/Zot/Receiver.php4
-rw-r--r--Zotlabs/Zot/Verify.php16
-rw-r--r--Zotlabs/Zot/ZotHandler.php4
105 files changed, 3132 insertions, 642 deletions
diff --git a/Zotlabs/Daemon/Deliver.php b/Zotlabs/Daemon/Deliver.php
index dbc311cf5..394a7bf3e 100644
--- a/Zotlabs/Daemon/Deliver.php
+++ b/Zotlabs/Daemon/Deliver.php
@@ -53,6 +53,9 @@ class Deliver {
remove_queue_item($r[0]['outq_hash']);
if($dresult && is_array($dresult)) {
+
+ // delivery reports for local deliveries do not require encryption
+
foreach($dresult as $xx) {
if(is_array($xx) && array_key_exists('message_id',$xx)) {
if(delivery_report_is_storable($xx)) {
diff --git a/Zotlabs/Daemon/Gprobe.php b/Zotlabs/Daemon/Gprobe.php
index 43cce93c3..f1ffb2d81 100644
--- a/Zotlabs/Daemon/Gprobe.php
+++ b/Zotlabs/Daemon/Gprobe.php
@@ -17,7 +17,7 @@ class Gprobe {
if(! strpos($url,'@'))
return;
- $r = q("select * from xchan where xchan_addr = '%s' limit 1",
+ $r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
dbesc($url)
);
diff --git a/Zotlabs/Daemon/Importfile.php b/Zotlabs/Daemon/Importfile.php
new file mode 100644
index 000000000..c68ed21cf
--- /dev/null
+++ b/Zotlabs/Daemon/Importfile.php
@@ -0,0 +1,47 @@
+<?php /** @file */
+
+namespace Zotlabs\Daemon;
+
+class Importfile {
+
+ static public function run($argc,$argv){
+
+ logger('Importfile: ' . print_r($argv,true));
+
+ if($argc < 3)
+ return;
+
+ $channel = channelx_by_n($argv[1]);
+ if(! $channel)
+ return;
+
+ $srcfile = $argv[2];
+ $folder = (($argc > 3) ? $argv[3] : '');
+ $dstname = (($argc > 4) ? $argv[4] : '');
+
+ $hash = random_string();
+
+ $arr = [
+ 'src' => $srcfile,
+ 'filename' => (($dstname) ? $dstname : basename($srcfile)),
+ 'hash' => $hash,
+ 'allow_cid' => $channel['channel_allow_cid'],
+ 'allow_gid' => $channel['channel_allow_gid'],
+ 'deny_cid' => $channel['channel_deny_cid'],
+ 'deny_gid' => $channel['channel_deny_gid'],
+ 'preserve_original' => true,
+ 'replace' => true
+ ];
+
+ if($folder)
+ $arr['folder'] = $folder;
+
+ attach_store($channel,$channel['channel_hash'],'import',$arr);
+
+ $sync = attach_export_data($channel,$hash);
+ if($sync)
+ build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+
+ return;
+ }
+}
diff --git a/Zotlabs/Daemon/Notifier.php b/Zotlabs/Daemon/Notifier.php
index 6bca22025..d0175549b 100644
--- a/Zotlabs/Daemon/Notifier.php
+++ b/Zotlabs/Daemon/Notifier.php
@@ -59,14 +59,19 @@ require_once('include/bbcode.php');
*
* ZOT
* permission_create abook_id
+ * permission_accept abook_id
+ * permission_reject abook_id
* permission_update abook_id
* refresh_all channel_id
* purge_all channel_id
* expire channel_id
* relay item_id (item was relayed to owner, we will deliver it as owner)
+ * single_activity item_id (deliver to a singleton network from the appropriate clone)
+ * single_mail mail_id (deliver to a singleton network from the appropriate clone)
* location channel_id
* request channel_id xchan_hash message_id
* rating xlink_id
+ * keychange channel_id
*
*/
@@ -103,7 +108,7 @@ class Notifier {
$normal_mode = true;
$packet_type = 'undefined';
- if($cmd === 'mail') {
+ if($cmd === 'mail' || $cmd === 'single_mail') {
$normal_mode = false;
$mail = true;
$private = true;
@@ -144,7 +149,21 @@ class Notifier {
$packet_type = 'request';
$normal_mode = false;
}
- elseif($cmd == 'permission_update' || $cmd == 'permission_create') {
+ elseif($cmd === 'keychange') {
+ $channel = channelx_by_n($item_id);
+ $r = q("select abook_xchan from abook where abook_channel = %d",
+ intval($item_id)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $recipients[] = $rr['abook_xchan'];
+ }
+ }
+ $private = false;
+ $packet_type = 'keychange';
+ $normal_mode = false;
+ }
+ elseif(in_array($cmd, [ 'permission_update', 'permission_reject', 'permission_accept', 'permission_create' ])) {
// Get the (single) recipient
$r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_self = 0",
intval($item_id)
@@ -156,8 +175,12 @@ class Notifier {
if($channel) {
$perm_update = array('sender' => $channel, 'recipient' => $r[0], 'success' => false, 'deliveries' => '');
- if($cmd == 'permission_create')
+ if($cmd === 'permission_create')
call_hooks('permissions_create',$perm_update);
+ elseif($cmd === 'permission_accept')
+ call_hooks('permissions_accept',$perm_update);
+ elseif($cmd === 'permission_reject')
+ call_hooks('permissions_reject',$perm_update);
else
call_hooks('permissions_update',$perm_update);
@@ -261,7 +284,7 @@ class Notifier {
$deleted_item = true;
}
- if(intval($target_item['item_type']) != ITEM_TYPE_POST) {
+ if(! in_array(intval($target_item['item_type']), [ ITEM_TYPE_POST ] )) {
logger('notifier: target item not forwardable: type ' . $target_item['item_type'], LOGGER_DEBUG);
return;
}
@@ -410,7 +433,7 @@ class Notifier {
$env_recips = (($private) ? array() : null);
- $details = q("select xchan_hash, xchan_instance_url, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . implode(',',$recipients) . ")");
+ $details = q("select xchan_hash, xchan_instance_url, xchan_network, xchan_addr, xchan_guid, xchan_guid_sig from xchan where xchan_hash in (" . protect_sprintf(implode(',',$recipients)) . ")");
$recip_list = array();
@@ -445,7 +468,7 @@ class Notifier {
'uplink' => $uplink,
'cmd' => $cmd,
'mail' => $mail,
- 'single' => false,
+ 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
'location' => $location,
'request' => $request,
'normal_mode' => $normal_mode,
@@ -477,7 +500,7 @@ class Notifier {
// Now we have collected recipients (except for external mentions, FIXME)
// Let's reduce this to a set of hubs; checking that the site is not dead.
- $r = q("select hubloc.*, site.site_crypto from hubloc left join site on site_url = hubloc_url where hubloc_hash in (" . implode(',',$recipients) . ")
+ $r = q("select hubloc.*, site.site_crypto, site.site_flags from hubloc left join site on site_url = hubloc_url where hubloc_hash in (" . protect_sprintf(implode(',',$recipients)) . ")
and hubloc_error = 0 and hubloc_deleted = 0 and ( site_dead = 0 OR site_dead is null ) "
);
@@ -518,14 +541,14 @@ class Notifier {
if($hub['hubloc_network'] == 'zot') {
if(! in_array($hub['hubloc_sitekey'],$keys)) {
- $hublist[] = $hub['hubloc_host'];
+ $hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network'];
$dhubs[] = $hub;
$keys[] = $hub['hubloc_sitekey'];
}
}
else {
if(! in_array($hub['hubloc_url'],$urls)) {
- $hublist[] = $hub['hubloc_host'];
+ $hublist[] = $hub['hubloc_host'] . ' ' . $hub['hubloc_network'];
$dhubs[] = $hub;
$urls[] = $hub['hubloc_url'];
}
@@ -553,7 +576,7 @@ class Notifier {
'uplink' => $uplink,
'cmd' => $cmd,
'mail' => $mail,
- 'single' => false,
+ 'single' => (($cmd === 'single_mail' || $cmd === 'single_activity') ? true : false),
'location' => $location,
'request' => $request,
'normal_mode' => $normal_mode,
@@ -572,12 +595,32 @@ class Notifier {
}
- $hash = random_string();
+ // singleton deliveries by definition 'not got zot'.
+ // Single deliveries are other federated networks (plugins) and we're essentially
+ // delivering only to those that have this site url in their abook_instance
+ // and only from within a sync operation. This means if you post from a clone,
+ // and a connection is connected to one of your other clones; assuming that hub
+ // is running it will receive a sync packet. On receipt of this sync packet it
+ // will invoke a delivery to those connections which are connected to just that
+ // hub instance.
+
+ if($cmd === 'single_mail' || $cmd === 'single_activity') {
+ continue;
+ }
+
+ // default: zot protocol
+
+ $hash = random_string();
$packet = null;
+ $pmsg = '';
if($packet_type === 'refresh' || $packet_type === 'purge') {
$packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
}
+ if($packet_type === 'keychange') {
+ $packet = zot_build_packet($channel,$packet_type,(($packet_recips) ? $packet_recips : null));
+ $pmsg = get_pconfig($channel['channel_id'],'system','keychange');
+ }
elseif($packet_type === 'request') {
$env = (($hub_env && $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']]) ? $hub_env[$hub['hubloc_host'] . $hub['hubloc_sitekey']] : '');
$packet = zot_build_packet($channel,$packet_type,$env,$hub['hubloc_sitekey'],$hub['site_crypto'],
@@ -591,7 +634,8 @@ class Notifier {
'account_id' => $channel['channel_account_id'],
'channel_id' => $channel['channel_id'],
'posturl' => $hub['hubloc_callback'],
- 'notify' => $packet
+ 'notify' => $packet,
+ 'msg' => (($pmsg) ? json_encode($pmsg) : '')
));
}
else {
diff --git a/Zotlabs/Lib/ActivityStreams.php b/Zotlabs/Lib/ActivityStreams.php
new file mode 100644
index 000000000..379e78a59
--- /dev/null
+++ b/Zotlabs/Lib/ActivityStreams.php
@@ -0,0 +1,199 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+class ActivityStreams {
+
+ public $data;
+ public $valid = false;
+ public $id = '';
+ public $type = '';
+ public $actor = null;
+ public $obj = null;
+ public $tgt = null;
+ public $origin = null;
+ public $owner = null;
+ public $signer = null;
+ public $ldsig = null;
+ public $sigok = false;
+ public $recips = null;
+ public $raw_recips = null;
+
+ function __construct($string) {
+
+ $this->data = json_decode($string,true);
+ if($this->data) {
+ $this->valid = true;
+ }
+
+ if($this->is_valid()) {
+ $this->id = $this->get_property_obj('id');
+ $this->type = $this->get_primary_type();
+ $this->actor = $this->get_compound_property('actor');
+ $this->obj = $this->get_compound_property('object');
+ $this->tgt = $this->get_compound_property('target');
+ $this->origin = $this->get_compound_property('origin');
+ $this->recips = $this->collect_recips();
+
+ $this->ldsig = $this->get_compound_property('signature');
+ if($this->ldsig) {
+ $this->signer = $this->get_compound_property('creator',$this->ldsig);
+ if($this->signer && $this->signer['publicKey'] && $this->signer['publicKey']['publicKeyPem']) {
+ $this->sigok = \Zotlabs\Lib\LDSignatures::verify($this->data,$this->signer['publicKey']['publicKeyPem']);
+ }
+ }
+
+ if(($this->type === 'Note') && (! $this->obj)) {
+ $this->obj = $this->data;
+ $this->type = 'Create';
+ }
+ }
+ }
+
+ function is_valid() {
+ return $this->valid;
+ }
+
+ function set_recips($arr) {
+ $this->saved_recips = $arr;
+ }
+
+ function collect_recips($base = '',$namespace = '') {
+ $x = [];
+ $fields = [ 'to','cc','bto','bcc','audience'];
+ foreach($fields as $f) {
+ $y = $this->get_compound_property($f,$base,$namespace);
+ if($y) {
+ $x = array_merge($x,$y);
+ if(! is_array($this->raw_recips))
+ $this->raw_recips = [];
+ $this->raw_recips[$f] = $x;
+ }
+ }
+// not yet ready for prime time
+// $x = $this->expand($x,$base,$namespace);
+ return $x;
+ }
+
+ function expand($arr,$base = '',$namespace = '') {
+ $ret = [];
+
+ // right now use a hardwired recursion depth of 5
+
+ for($z = 0; $z < 5; $z ++) {
+ if(is_array($arr) && $arr) {
+ foreach($arr as $a) {
+ if(is_array($a)) {
+ $ret[] = $a;
+ }
+ else {
+ $x = $this->get_compound_property($a,$base,$namespace);
+ if($x) {
+ $ret = array_merge($ret,$x);
+ }
+ }
+ }
+ }
+ }
+
+ // @fixme de-duplicate
+
+ return $ret;
+ }
+
+ function get_namespace($base,$namespace) {
+
+ if(! $namespace)
+ return '';
+
+ $key = null;
+
+
+ foreach( [ $this->data, $base ] as $b ) {
+ if(! $b)
+ continue;
+ if(array_key_exists('@context',$b)) {
+ if(is_array($b['@context'])) {
+ foreach($b['@context'] as $ns) {
+ if(is_array($ns)) {
+ foreach($ns as $k => $v) {
+ if($namespace === $v)
+ $key = $k;
+ }
+ }
+ else {
+ if($namespace === $ns) {
+ $key = '';
+ }
+ }
+ }
+ }
+ else {
+ if($namespace === $b['@context']) {
+ $key = '';
+ }
+ }
+ }
+ }
+ return $key;
+ }
+
+
+ function get_property_obj($property,$base = '',$namespace = '' ) {
+ $prefix = $this->get_namespace($base,$namespace);
+ if($prefix === null)
+ return null;
+ $base = (($base) ? $base : $this->data);
+ $propname = (($prefix) ? $prefix . ':' : '') . $property;
+ return ((array_key_exists($propname,$base)) ? $base[$propname] : null);
+ }
+
+ function fetch_property($url) {
+ $redirects = 0;
+ if(! check_siteallowed($url)) {
+ logger('blacklisted: ' . $url);
+ return null;
+ }
+
+ $x = z_fetch_url($url,true,$redirects,
+ ['headers' => [ 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json' ]]);
+ if($x['success'])
+ return json_decode($x['body'],true);
+ return null;
+ }
+
+ function get_compound_property($property,$base = '',$namespace = '') {
+ $x = $this->get_property_obj($property,$base,$namespace);
+ if($this->is_url($x)) {
+ $x = $this->fetch_property($x);
+ }
+ return $x;
+ }
+
+ function is_url($url) {
+ if(($url) && (! is_array($url)) && (strpos($url,'http') === 0)) {
+ return true;
+ }
+ return false;
+ }
+
+ function get_primary_type($base = '',$namespace = '') {
+ if(! $base)
+ $base = $this->data;
+ $x = $this->get_property_obj('type',$base,$namespace);
+ if(is_array($x)) {
+ foreach($x as $y) {
+ if(strpos($y,':') === false) {
+ return $y;
+ }
+ }
+ }
+ return $x;
+ }
+
+ function debug() {
+ $x = var_export($this,true);
+ return $x;
+ }
+
+} \ No newline at end of file
diff --git a/Zotlabs/Lib/ActivityStreams2.php b/Zotlabs/Lib/ActivityStreams2.php
deleted file mode 100644
index 904782bf7..000000000
--- a/Zotlabs/Lib/ActivityStreams2.php
+++ /dev/null
@@ -1,86 +0,0 @@
-<?php
-
-namespace Zotlabs\Lib;
-
-
-class ActivityStreams2 {
-
- public $data;
- public $valid = false;
- public $id = '';
- public $type = '';
- public $actor = null;
- public $obj = null;
- public $tgt = null;
-
- function __construct($string) {
-
- $this->data = json_decode($string,true);
- if($this->data) {
- $this->valid = true;
- }
-
- if($this->is_valid()) {
- $this->id = $this->get_property_obj('id');
- $this->type = $this->get_primary_type();
- $this->actor = $this->get_compound_property('actor');
- $this->obj = $this->get_compound_property('object');
- $this->tgt = $this->get_compound_property('target');
- }
- }
-
- function is_valid() {
- return $this->valid;
- }
-
- function get_property_obj($property,$base = '') {
- if(! $base) {
- $base = $this->data;
- }
- return $base[$property];
- }
-
- function fetch_property($url) {
- $redirects = 0;
- $x = z_fetch_url($url,true,$redirects,
- ['headers' => [ 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"']]);
- if($x['success'])
- return json_decode($x['body'],true);
- return null;
- }
-
- function get_compound_property($property,$base = '') {
- $x = $this->get_property_obj($property,$base);
- if($this->is_url($x)) {
- $x = $this->fetch_property($x);
- }
- return $x;
- }
-
- function is_url($url) {
- if(($url) && (! is_array($url)) && (strpos($url,'http') === 0)) {
- return true;
- }
- return false;
- }
-
- function get_primary_type($base = '') {
- if(! $base)
- $base = $this->data;
- $x = $this->get_property_obj('type',$base);
- if(is_array($x)) {
- foreach($x as $y) {
- if(strpos($y,':') === false) {
- return $y;
- }
- }
- }
- return $x;
- }
-
- function debug() {
- $x = var_export($this,true);
- return $x;
- }
-
-} \ No newline at end of file
diff --git a/Zotlabs/Lib/Apps.php b/Zotlabs/Lib/Apps.php
index 68587df49..f13fbe362 100644
--- a/Zotlabs/Lib/Apps.php
+++ b/Zotlabs/Lib/Apps.php
@@ -169,6 +169,14 @@ class Apps {
$requires = explode(',',$ret['requires']);
foreach($requires as $require) {
$require = trim(strtolower($require));
+ $config = false;
+
+ if(substr($require, 0, 7) == 'config:') {
+ $config = true;
+ $require = ltrim($require, 'config:');
+ $require = explode('=', $require);
+ }
+
switch($require) {
case 'nologin':
if(local_channel())
@@ -191,10 +199,13 @@ class Apps {
unset($ret);
break;
default:
- if(! (local_channel() && feature_enabled(local_channel(),$require)))
+ if($config)
+ $unset = ((get_config('system', $require[0]) == $require[1]) ? false : true);
+ else
+ $unset = ((local_channel() && feature_enabled(local_channel(),$require)) ? false : true);
+ if($unset)
unset($ret);
break;
-
}
}
}
@@ -210,7 +221,8 @@ class Apps {
static public function translate_system_apps(&$arr) {
$apps = array(
'Apps' => t('Apps'),
- 'Site Admin' => t('Site Admin'),
+ 'Cards' => t('Cards'),
+ 'Admin' => t('Site Admin'),
'Report Bug' => t('Report Bug'),
'View Bookmarks' => t('View Bookmarks'),
'My Chatrooms' => t('My Chatrooms'),
@@ -305,8 +317,17 @@ class Apps {
if($k === 'requires') {
$requires = explode(',',$v);
+
foreach($requires as $require) {
$require = trim(strtolower($require));
+ $config = false;
+
+ if(substr($require, 0, 7) == 'config:') {
+ $config = true;
+ $require = ltrim($require, 'config:');
+ $require = explode('=', $require);
+ }
+
switch($require) {
case 'nologin':
if(local_channel())
@@ -330,10 +351,13 @@ class Apps {
return '';
break;
default:
- if(! (local_channel() && feature_enabled(local_channel(),$require)))
+ if($config)
+ $unset = ((get_config('system', $require[0]) == $require[1]) ? false : true);
+ else
+ $unset = ((local_channel() && feature_enabled(local_channel(),$require)) ? false : true);
+ if($unset)
return '';
break;
-
}
}
}
@@ -359,6 +383,13 @@ class Apps {
$install_action = (($installed) ? t('Update') : t('Install'));
$icon = ((strpos($papp['photo'],'icon:') === 0) ? substr($papp['photo'],5) : '');
+ if($mode === 'navbar') {
+ return replace_macros(get_markup_template('app_nav.tpl'),array(
+ '$app' => $papp,
+ '$icon' => $icon,
+ ));
+ }
+
return replace_macros(get_markup_template('app.tpl'),array(
'$app' => $papp,
'$icon' => $icon,
diff --git a/Zotlabs/Lib/Enotify.php b/Zotlabs/Lib/Enotify.php
index 9f3347d19..e82c11a35 100644
--- a/Zotlabs/Lib/Enotify.php
+++ b/Zotlabs/Lib/Enotify.php
@@ -130,7 +130,9 @@ class Enotify {
if ($params['type'] == NOTIFY_COMMENT) {
// logger("notification: params = " . print_r($params, true), LOGGER_DEBUG);
- $itemlink = $params['link'];
+ $moderated = (($params['item']['item_blocked'] == ITEM_MODERATED) ? true : false);
+
+ $itemlink = $params['link'];
// ignore like/unlike activity on posts - they probably require a separate notification preference
@@ -170,8 +172,6 @@ class Enotify {
xchan_query($p);
- $moderated = (($p[0]['item_blocked'] == ITEM_MODERATED) ? true : false);
-
$item_post_type = item_post_type($p[0]);
// $private = $p[0]['item_private'];
$parent_id = $p[0]['id'];
diff --git a/Zotlabs/Lib/JSalmon.php b/Zotlabs/Lib/JSalmon.php
new file mode 100644
index 000000000..43d5f9d09
--- /dev/null
+++ b/Zotlabs/Lib/JSalmon.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+
+class JSalmon {
+
+ static function sign($data,$key_id,$key) {
+
+ $arr = $data;
+ $data = json_encode($data,JSON_UNESCAPED_SLASHES);
+ $data = base64url_encode($data, false); // do not strip padding
+ $data_type = 'application/x-zot+json';
+ $encoding = 'base64url';
+ $algorithm = 'RSA-SHA256';
+
+ $data = preg_replace('/\s+/','',$data);
+
+ // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
+
+ $precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
+
+ $signature = base64url_encode(rsa_sign($data . $precomputed, $key), false);
+
+ return ([
+ 'signed' => true,
+ 'data' => $data,
+ 'data_type' => $data_type,
+ 'encoding' => $encoding,
+ 'alg' => $algorithm,
+ 'sigs' => [
+ 'value' => $signature,
+ 'key_id' => base64url_encode($key_id)
+ ]
+ ]);
+
+ }
+} \ No newline at end of file
diff --git a/Zotlabs/Lib/LDSignatures.php b/Zotlabs/Lib/LDSignatures.php
new file mode 100644
index 000000000..6d7127cde
--- /dev/null
+++ b/Zotlabs/Lib/LDSignatures.php
@@ -0,0 +1,135 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+require_once('library/jsonld/jsonld.php');
+
+class LDSignatures {
+
+
+ static function verify($data,$pubkey) {
+
+ $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);
+ logger('LD-verify: ' . intval($x));
+
+ return $x;
+ }
+
+ static function dopplesign(&$data,$channel) {
+ // remove for the time being - performance issues
+ // $data['magicEnv'] = self::salmon_sign($data,$channel);
+ return self::sign($data,$channel);
+ }
+
+ static function sign($data,$channel) {
+
+ $options = [
+ 'type' => 'RsaSignature2017',
+ 'nonce' => random_string(64),
+ 'creator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
+ 'created' => datetime_convert('UTC','UTC', 'now', 'Y-m-d\Th:i:s\Z')
+ ];
+
+ $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']));
+
+ $signed = array_merge([
+ '@context' => [
+ ACTIVITYSTREAMS_JSONLD_REV,
+ 'https://w3id.org/security/v1' ],
+ ],$options);
+
+ return $signed;
+ }
+
+
+ static function signable_data($data) {
+
+ $newdata = [];
+ if($data) {
+ foreach($data as $k => $v) {
+ if(! in_array($k,[ 'signature' ])) {
+ $newdata[$k] = $v;
+ }
+ }
+ }
+ return json_encode($newdata,JSON_UNESCAPED_SLASHES);
+ }
+
+
+ static function signable_options($options) {
+
+ $newopts = [ '@context' => 'https://w3id.org/identity/v1' ];
+ if($options) {
+ foreach($options as $k => $v) {
+ if(! in_array($k,[ 'type','id','signatureValue' ])) {
+ $newopts[$k] = $v;
+ }
+ }
+ }
+ return json_encode($newopts,JSON_UNESCAPED_SLASHES);
+ }
+
+ static function hash($obj) {
+
+ return hash('sha256',self::normalise($obj));
+ }
+
+ static function normalise($data) {
+ if(is_string($data)) {
+ $data = json_decode($data);
+ }
+
+ if(! is_object($data))
+ return '';
+
+ jsonld_set_document_loader('jsonld_document_loader');
+
+ try {
+ $d = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
+ }
+ catch (\Exception $e) {
+ logger('normalise error:' . print_r($e,true));
+ logger('normalise error: ' . print_r($data,true));
+ }
+
+ return $d;
+ }
+
+ static function salmon_sign($data,$channel) {
+
+ $arr = $data;
+ $data = json_encode($data,JSON_UNESCAPED_SLASHES);
+ $data = base64url_encode($data, false); // do not strip padding
+ $data_type = 'application/activity+json';
+ $encoding = 'base64url';
+ $algorithm = 'RSA-SHA256';
+ $keyhash = base64url_encode(z_root() . '/channel/' . $channel['channel_address']);
+
+ $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$data);
+
+ // precomputed base64url encoding of data_type, encoding, algorithm concatenated with periods
+
+ $precomputed = '.' . base64url_encode($data_type,false) . '.YmFzZTY0dXJs.UlNBLVNIQTI1Ng==';
+
+ $signature = base64url_encode(rsa_sign($data . $precomputed,$channel['channel_prvkey']));
+
+ return ([
+ 'id' => $arr['id'],
+ 'meData' => $data,
+ 'meDataType' => $data_type,
+ 'meEncoding' => $encoding,
+ 'meAlgorithm' => $algorithm,
+ 'meCreator' => z_root() . '/channel/' . $channel['channel_address'] . '/public_key_pem',
+ 'meSignatureValue' => $signature
+ ]);
+
+ }
+
+
+
+} \ No newline at end of file
diff --git a/Zotlabs/Lib/MarkdownSoap.php b/Zotlabs/Lib/MarkdownSoap.php
index 534ad819f..fa279b07c 100644
--- a/Zotlabs/Lib/MarkdownSoap.php
+++ b/Zotlabs/Lib/MarkdownSoap.php
@@ -94,7 +94,7 @@ class MarkdownSoap {
}
function escape($s) {
- return htmlspecialchars($s,ENT_QUOTES);
+ return htmlspecialchars($s,ENT_QUOTES,'UTF-8',false);
}
static public function unescape($s) {
diff --git a/Zotlabs/Lib/NativeWiki.php b/Zotlabs/Lib/NativeWiki.php
index 4301feaa0..7642dbb3e 100644
--- a/Zotlabs/Lib/NativeWiki.php
+++ b/Zotlabs/Lib/NativeWiki.php
@@ -18,11 +18,18 @@ class NativeWiki {
if($wikis) {
foreach($wikis as &$w) {
+
+ $w['json_allow_cid'] = acl2json($w['allow_cid']);
+ $w['json_allow_gid'] = acl2json($w['allow_gid']);
+ $w['json_deny_cid'] = acl2json($w['deny_cid']);
+ $w['json_deny_gid'] = acl2json($w['deny_gid']);
+
$w['rawName'] = get_iconfig($w, 'wiki', 'rawName');
$w['htmlName'] = escape_tags($w['rawName']);
$w['urlName'] = urlencode(urlencode($w['rawName']));
$w['mimeType'] = get_iconfig($w, 'wiki', 'mimeType');
- $w['lock'] = (($w['item_private'] || $w['allow_cid'] || $w['allow_gid'] || $w['deny_cid'] || $w['deny_gid']) ? true : false);
+ $w['typelock'] = get_iconfig($w, 'wiki', 'typelock');
+ $w['lockstate'] = (($w['allow_cid'] || $w['allow_gid'] || $w['deny_cid'] || $w['deny_gid']) ? 'lock' : 'unlock');
}
}
// TODO: query db for wikis the observer can access. Return with two lists, for read and write access
@@ -84,7 +91,9 @@ class NativeWiki {
if(! set_iconfig($arr, 'wiki', 'mimeType', $wiki['mimeType'], true)) {
return array('item' => null, 'success' => false);
}
-
+
+ set_iconfig($arr,'wiki','typelock',$wiki['typelock'],true);
+
$post = item_store($arr);
$item_id = $post['item_id'];
@@ -98,6 +107,61 @@ class NativeWiki {
}
}
+ function update_wiki($channel_id, $observer_hash, $arr, $acl) {
+
+ $w = self::get_wiki($channel_id, $observer_hash, $arr['resource_id']);
+ $item = $w['wiki'];
+
+ if(! $item) {
+ return array('item' => null, 'success' => false);
+ }
+
+ $x = $acl->get();
+
+ $item['allow_cid'] = $x['allow_cid'];
+ $item['allow_gid'] = $x['allow_gid'];
+ $item['deny_cid'] = $x['deny_cid'];
+ $item['deny_gid'] = $x['deny_gid'];
+ $item['item_private'] = intval($acl->is_private());
+
+ $update_title = false;
+
+ if($item['title'] !== $arr['updateRawName']) {
+ $update_title = true;
+ $item['title'] = $arr['updateRawName'];
+ }
+
+ $update = item_store_update($item);
+
+ $item_id = $update['item_id'];
+
+ // update acl for any existing wiki pages
+
+ q("update item set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d where resource_type = 'nwikipage' and resource_id = '%s'",
+ dbesc($item['allow_cid']),
+ dbesc($item['allow_gid']),
+ dbesc($item['deny_cid']),
+ dbesc($item['deny_gid']),
+ dbesc($item['item_private']),
+ dbesc($arr['resource_id'])
+ );
+
+
+ if($update['item_id']) {
+ info( t('Wiki updated successfully'));
+ if($update_title) {
+ // Update the wiki name information using iconfig.
+ if(! set_iconfig($update['item_id'], 'wiki', 'rawName', $arr['updateRawName'], true)) {
+ return array('item' => null, 'success' => false);
+ }
+ }
+ return array('item' => $update['item'], 'item_id' => $update['item_id'], 'success' => $update['success']);
+ }
+ else {
+ return array('item' => null, 'success' => false);
+ }
+ }
+
static public function sync_a_wiki_item($uid,$id,$resource_id) {
@@ -108,6 +172,12 @@ class NativeWiki {
dbesc($resource_id)
);
if($r) {
+ $q = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s'",
+ dbesc($r[0]['resource_type'])
+ );
+ if($q) {
+ $r = array_merge($r,$q);
+ }
xchan_query($r);
$sync_item = fetch_post_tags($r);
build_sync_packet($uid,array('wiki' => array(encode_item($sync_item[0],true))));
@@ -150,13 +220,15 @@ class NativeWiki {
// Get wiki metadata
$rawName = get_iconfig($w, 'wiki', 'rawName');
$mimeType = get_iconfig($w, 'wiki', 'mimeType');
+ $typelock = get_iconfig($w, 'wiki', 'typelock');
return array(
- 'wiki' => $w,
- 'rawName' => $rawName,
+ 'wiki' => $w,
+ 'rawName' => $rawName,
'htmlName' => escape_tags($rawName),
- 'urlName' => urlencode(urlencode($rawName)),
- 'mimeType' => $mimeType
+ 'urlName' => urlencode(urlencode($rawName)),
+ 'mimeType' => $mimeType,
+ 'typelock' => $typelock
);
}
}
diff --git a/Zotlabs/Lib/NativeWikiPage.php b/Zotlabs/Lib/NativeWikiPage.php
index 78b54ebda..209a5ef3c 100644
--- a/Zotlabs/Lib/NativeWikiPage.php
+++ b/Zotlabs/Lib/NativeWikiPage.php
@@ -21,7 +21,7 @@ class NativeWikiPage {
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
$r = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' and uid = %d and item_deleted = 0
- $sql_extra order by created asc",
+ $sql_extra order by title asc",
dbesc($resource_id),
intval($channel_id)
);
@@ -55,7 +55,12 @@ class NativeWikiPage {
}
- static public function create_page($channel_id, $observer_hash, $name, $resource_id) {
+ static public function create_page($channel_id, $observer_hash, $name, $resource_id, $mimetype = 'text/bbcode') {
+
+ logger('mimetype: ' . $mimetype);
+
+ if(! in_array($mimetype,[ 'text/markdown','text/bbcode','text/plain','text/html' ]))
+ $mimetype = 'text/markdown';
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
@@ -68,6 +73,8 @@ class NativeWikiPage {
$arr = [];
$arr['uid'] = $channel_id;
$arr['author_xchan'] = $observer_hash;
+ $arr['mimetype'] = $mimetype;
+ $arr['title'] = $name;
$arr['resource_type'] = 'nwikipage';
$arr['resource_id'] = $resource_id;
$arr['allow_cid'] = $w['wiki']['allow_cid'];
@@ -133,8 +140,14 @@ class NativeWikiPage {
if($ic) {
foreach($ic as $c) {
set_iconfig($c['item_id'],'nwikipage','pagetitle',$pageNewName);
+ $ids[] = $c['item_id'];
}
+ $str_ids = implode(',', $ids);
+ q("update item set title = '%s' where id in ($str_ids)",
+ dbesc($pageNewName)
+ );
+
$page = [
'rawName' => $pageNewName,
'htmlName' => escape_tags($pageNewName),
@@ -167,10 +180,11 @@ class NativeWikiPage {
$content = $item['body'];
return [
- 'content' => $content,
- 'mimeType' => $w['mimeType'],
- 'message' => '',
- 'success' => true
+ 'content' => $content,
+ 'mimeType' => $w['mimeType'],
+ 'pageMimeType' => $item['mimetype'],
+ 'message' => '',
+ 'success' => true
];
}
@@ -333,7 +347,6 @@ class NativeWikiPage {
return array('message' => t('Error reading wiki'), 'success' => false);
}
- $mimetype = $w['mimeType'];
// fetch the most recently saved revision.
@@ -342,6 +355,8 @@ class NativeWikiPage {
return array('message' => t('Page not found'), 'success' => false);
}
+ $mimetype = $item['mimetype'];
+
// change just the fields we need to change to create a revision;
unset($item['id']);
@@ -599,10 +614,13 @@ class NativeWikiPage {
}
static public function get_file_ext($arr) {
- if($arr['mimeType'] == 'text/bbcode')
+ if($arr['mimetype'] === 'text/bbcode')
return '.bb';
- else
+ elseif($arr['mimetype'] === 'text/markdown')
return '.md';
+ elseif($arr['mimetype'] === 'text/plain')
+ return '.txt';
+
}
// This function is derived from
diff --git a/Zotlabs/Lib/PConfig.php b/Zotlabs/Lib/PConfig.php
index 25478e764..2a0b18aac 100644
--- a/Zotlabs/Lib/PConfig.php
+++ b/Zotlabs/Lib/PConfig.php
@@ -20,11 +20,12 @@ class PConfig {
if(is_null($uid) || $uid === false)
return false;
- if(! array_key_exists($uid, \App::$config))
- \App::$config[$uid] = array();
-
if(! is_array(\App::$config)) {
- btlogger('App::$config not an array: ' . $uid);
+ btlogger('App::$config not an array');
+ }
+
+ if(! array_key_exists($uid, \App::$config)) {
+ \App::$config[$uid] = array();
}
if(! is_array(\App::$config[$uid])) {
diff --git a/Zotlabs/Lib/SConfig.php b/Zotlabs/Lib/SConfig.php
new file mode 100644
index 000000000..ca0d133b2
--- /dev/null
+++ b/Zotlabs/Lib/SConfig.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Zotlabs\Lib;
+
+// account configuration storage is built on top of the under-utilised xconfig
+
+class SConfig {
+
+ static public function Load($server_id) {
+ return XConfig::Load('s_' . $server_id);
+ }
+
+ static public function Get($server_id,$family,$key,$default = false) {
+ return XConfig::Get('s_' . $server_id,$family,$key, $default);
+ }
+
+ static public function Set($server_id,$family,$key,$value) {
+ return XConfig::Set('s_' . $server_id,$family,$key,$value);
+ }
+
+ static public function Delete($server_id,$family,$key) {
+ return XConfig::Delete('s_' . $server_id,$family,$key);
+ }
+
+}
diff --git a/Zotlabs/Lib/System.php b/Zotlabs/Lib/System.php
index a5790fb07..c3e11eb6a 100644
--- a/Zotlabs/Lib/System.php
+++ b/Zotlabs/Lib/System.php
@@ -61,6 +61,13 @@ class System {
return 'pro';
}
+
+ static public function get_zot_revision() {
+ $x = [ 'revision' => ZOT_REVISION ];
+ call_hooks('zot_revision',$x);
+ return $x['revision'];
+ }
+
static public function get_std_version() {
if(defined('STD_VERSION'))
return STD_VERSION;
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php
index 17d65dbc7..67a507025 100644
--- a/Zotlabs/Lib/ThreadItem.php
+++ b/Zotlabs/Lib/ThreadItem.php
@@ -29,6 +29,7 @@ class ThreadItem {
private $visiting = false;
private $channel = null;
private $display_mode = 'normal';
+ private $reload = '';
public function __construct($data) {
@@ -101,10 +102,13 @@ class ThreadItem {
if($item['author']['xchan_network'] === 'rss')
$shareable = true;
+
$mode = $conv->get_mode();
+ $edlink = (($item['item_type'] == ITEM_TYPE_CARD) ? 'card_edit' : 'editpost');
+
if(local_channel() && $observer['xchan_hash'] === $item['author_xchan'])
- $edpost = array(z_root()."/editpost/".$item['id'], t("Edit"));
+ $edpost = array(z_root() . '/' . $edlink . '/' . $item['id'], t('Edit'));
else
$edpost = false;
@@ -309,7 +313,8 @@ class ThreadItem {
$tmp_item = array(
'template' => $this->get_template(),
- 'mode' => $mode,
+ 'mode' => $mode,
+ 'item_type' => intval($item['item_type']),
'type' => implode("",array_slice(explode("/",$item['verb']),-1)),
'body' => $body['html'],
'tags' => $body['tags'],
@@ -407,8 +412,9 @@ class ThreadItem {
'showdislike' => $showdislike,
'comment' => $this->get_comment_box($indent),
'previewing' => ($conv->is_preview() ? true : false ),
+ 'preview_lbl' => t('This is an unsaved preview'),
'wait' => t('Please wait'),
- 'submid' => str_replace(['+','='], ['',''], base64_encode(substr($item['mid'],0,32))),
+ 'submid' => str_replace(['+','='], ['',''], base64_encode($item['mid'])),
'thread_level' => $thread_level
);
@@ -479,6 +485,14 @@ class ThreadItem {
return $this->threaded;
}
+ public function set_reload($val) {
+ $this->reload = $val;
+ }
+
+ public function get_reload() {
+ return $this->reload;
+ }
+
public function set_commentable($val) {
$this->commentable = $val;
foreach($this->get_children() as $child)
@@ -715,7 +729,7 @@ class ThreadItem {
$comment_box = replace_macros($template,array(
'$return_path' => '',
'$threaded' => $this->is_threaded(),
- '$jsreload' => '', //(($conv->get_mode() === 'display') ? $_SESSION['return_url'] : ''),
+ '$jsreload' => $conv->reload,
'$type' => (($conv->get_mode() === 'channel') ? 'wall-comment' : 'net-comment'),
'$id' => $this->get_id(),
'$parent' => $this->get_id(),
@@ -733,19 +747,21 @@ class ThreadItem {
'$edquote' => t('Quote'),
'$edcode' => t('Code'),
'$edimg' => t('Image'),
+ '$edatt' => t('Attach File'),
'$edurl' => t('Insert Link'),
'$edvideo' => t('Video'),
'$preview' => t('Preview'), // ((feature_enabled($conv->get_profile_owner(),'preview')) ? t('Preview') : ''),
'$indent' => $indent,
+ '$can_upload' => (perm_is_allowed($conv->get_profile_owner(),get_observer_hash(),'write_storage') && $conv->is_uploadable()),
'$feature_encrypt' => ((feature_enabled($conv->get_profile_owner(),'content_encrypt')) ? true : false),
'$encrypt' => t('Encrypt text'),
'$cipher' => $conv->get_cipher(),
'$sourceapp' => \App::$sourcename,
'$observer' => get_observer_hash(),
- '$anoncomments' => (($conv->get_mode() === 'channel' && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
- '$anonname' => [ 'anonname', t('Your full name (required)'),'','','','onBlur="commentCloseUI(this,\'' . $this->get_id() . '\')"' ],
- '$anonmail' => [ 'anonmail', t('Your email address (required)'),'','','','onBlur="commentCloseUI(this,\'' . $this->get_id() . '\')"' ],
- '$anonurl' => [ 'anonurl', t('Your website URL (optional)'),'','','','onBlur="commentCloseUI(this,\'' . $this->get_id() . '\')"' ]
+ '$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(),'','post_comments')) ? true : false),
+ '$anonname' => [ 'anonname', t('Your full name (required)') ],
+ '$anonmail' => [ 'anonmail', t('Your email address (required)') ],
+ '$anonurl' => [ 'anonurl', t('Your website URL (optional)') ]
));
return $comment_box;
diff --git a/Zotlabs/Lib/ThreadStream.php b/Zotlabs/Lib/ThreadStream.php
index 35ccf4fdb..436723f8c 100644
--- a/Zotlabs/Lib/ThreadStream.php
+++ b/Zotlabs/Lib/ThreadStream.php
@@ -22,15 +22,17 @@ class ThreadStream {
private $profile_owner = 0;
private $preview = false;
private $prepared_item = '';
+ public $reload = '';
private $cipher = 'aes256';
// $prepared_item is for use by alternate conversation structures such as photos
// wherein we've already prepared a top level item which doesn't look anything like
// a normal "post" item
- public function __construct($mode, $preview, $prepared_item = '') {
+ public function __construct($mode, $preview, $uploadable, $prepared_item = '') {
$this->set_mode($mode);
$this->preview = $preview;
+ $this->uploadable = $uploadable;
$this->prepared_item = $prepared_item;
$c = ((local_channel()) ? get_pconfig(local_channel(),'system','default_cipher') : '');
if($c)
@@ -56,11 +58,17 @@ class ThreadStream {
$this->profile_owner = \App::$profile['profile_uid'];
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
break;
+ case 'cards':
+ $this->profile_owner = \App::$profile['profile_uid'];
+ $this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
+ $this->reload = $_SESSION['return_url'];
+ break;
case 'display':
// in this mode we set profile_owner after initialisation (from conversation()) and then
// pull some trickery which allows us to re-invoke this function afterward
// it's an ugly hack so @FIXME
$this->writable = perm_is_allowed($this->profile_owner,$ob_hash,'post_comments');
+ $this->uploadable = perm_is_allowed($this->profile_owner,$ob_hash,'write_storage');
break;
case 'page':
$this->profile_owner = \App::$profile['uid'];
@@ -92,6 +100,11 @@ class ThreadStream {
return $this->commentable;
}
+ public function is_uploadable() {
+ return $this->uploadable;
+ }
+
+
/**
* Check if page is a preview
*/
diff --git a/Zotlabs/Module/Acl.php b/Zotlabs/Module/Acl.php
index 83fafbdff..e164875e8 100644
--- a/Zotlabs/Module/Acl.php
+++ b/Zotlabs/Module/Acl.php
@@ -21,7 +21,7 @@ class Acl extends \Zotlabs\Web\Controller {
function init() {
- // logger('mod_acl: ' . print_r($_REQUEST,true));
+ logger('mod_acl: ' . print_r($_REQUEST,true));
$start = (x($_REQUEST,'start') ? $_REQUEST['start'] : 0);
$count = (x($_REQUEST,'count') ? $_REQUEST['count'] : 500);
@@ -33,6 +33,7 @@ class Acl extends \Zotlabs\Web\Controller {
// $type =
// '' => standard ACL request
// 'g' => Groups only ACL request
+ // 'f' => forums only ACL request
// 'c' => Connections only ACL request or editor (textarea) mention request
// $_REQUEST['search'] contains ACL search text.
@@ -56,12 +57,12 @@ class Acl extends \Zotlabs\Web\Controller {
$search = $_REQUEST['query'];
}
- if( (! local_channel()) && (! ($type == 'x' || $type == 'c')))
+ if( (! local_channel()) && (! in_array($type, [ 'x', 'c', 'f' ])))
killme();
$permitted = [];
- if(in_array($type, [ 'm', 'a', 'c' ])) {
+ if(in_array($type, [ 'm', 'a', 'c', 'f' ])) {
// These queries require permission checking. We'll create a simple array of xchan_hash for those with
// the requisite permissions which we can check against.
@@ -154,7 +155,7 @@ class Acl extends \Zotlabs\Web\Controller {
}
}
- if($type == '' || $type == 'c') {
+ if($type == '' || $type == 'c' || $type === 'f') {
$extra_channels_sql = '';
@@ -307,7 +308,7 @@ class Acl extends \Zotlabs\Web\Controller {
$contacts[] = array(
"photo" => $g['photo'],
"name" => $g['name'],
- "nick" => $g['address'],
+ "nick" => $g['address']
);
}
}
@@ -324,18 +325,24 @@ class Acl extends \Zotlabs\Web\Controller {
$r = array();
if($r) {
- foreach($r as $g){
+ foreach($r as $g) {
- // remove RSS feeds from ACLs - they are inaccessible
- if(strpos($g['hash'],'/') && $type != 'a')
+ if(($g['network'] === 'rss') && ($type != 'a'))
continue;
-
- if(in_array($g['hash'],$permitted) && $type == 'c' && (! $noforums)) {
+
+ $g['hash'] = urlencode($g['hash']);
+
+ if(! $g['nick']) {
+ $t = explode(' ',strtolower($g['name']));
+ $g['nick'] = $t[0] . '@';
+ }
+
+ if(in_array($g['hash'],$permitted) && in_array($type, [ 'c', 'f' ]) && (! $noforums)) {
$contacts[] = array(
"type" => "c",
"photo" => "images/twopeople.png",
- "name" => $g['name'] . '+',
- "id" => $g['id'] . '+',
+ "name" => $g['name'] . (($type === 'f') ? '' : '+'),
+ "id" => urlencode($g['id']) . (($type === 'f') ? '' : '+'),
"xid" => $g['hash'],
"link" => $g['nick'],
"nick" => substr($g['nick'],0,strpos($g['nick'],'@')),
@@ -344,18 +351,20 @@ class Acl extends \Zotlabs\Web\Controller {
"label" => t('network')
);
}
- $contacts[] = array(
- "type" => "c",
- "photo" => $g['micro'],
- "name" => $g['name'],
- "id" => $g['id'],
- "xid" => $g['hash'],
- "link" => $g['nick'],
- "nick" => (($g['nick']) ? substr($g['nick'],0,strpos($g['nick'],'@')) : t('RSS')),
- "self" => (intval($g['abook_self']) ? 'abook-self' : ''),
- "taggable" => '',
- "label" => '',
- );
+ if($type !== 'f') {
+ $contacts[] = array(
+ "type" => "c",
+ "photo" => $g['micro'],
+ "name" => $g['name'],
+ "id" => urlencode($g['id']),
+ "xid" => $g['hash'],
+ "link" => $g['nick'],
+ "nick" => (($g['nick']) ? substr($g['nick'],0,strpos($g['nick'],'@')) : $g['nick']),
+ "self" => (intval($g['abook_self']) ? 'abook-self' : ''),
+ "taggable" => '',
+ "label" => '',
+ );
+ }
}
}
diff --git a/Zotlabs/Module/Admin/Site.php b/Zotlabs/Module/Admin/Site.php
index 4c5b82e78..d3d058c53 100644
--- a/Zotlabs/Module/Admin/Site.php
+++ b/Zotlabs/Module/Admin/Site.php
@@ -62,6 +62,7 @@ class Site {
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
$techlevel_lock = ((x($_POST,'techlock')) ? intval($_POST['techlock']) : 0);
+ $imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
$techlevel = null;
if(array_key_exists('techlevel', $_POST))
@@ -82,6 +83,7 @@ class Site {
set_config('system', 'reply_address', $reply_address);
set_config('system', 'from_email', $from_email);
set_config('system', 'from_email_name' , $from_email_name);
+ set_config('system', 'imagick_convert_path' , $imagick_path);
set_config('system', 'techlevel_lock', $techlevel_lock);
@@ -206,7 +208,7 @@ class Site {
// directory server should not be set or settable unless we are a directory client
if($dirmode == DIRECTORY_MODE_NORMAL) {
- $x = q("select site_url from site where site_flags in (%d,%d) and site_realm = '%s'",
+ $x = q("select site_url from site where site_flags in (%d,%d) and site_realm = '%s' and site_dead = 0",
intval(DIRECTORY_MODE_SECONDARY),
intval(DIRECTORY_MODE_PRIMARY),
dbesc($realm)
@@ -317,6 +319,7 @@ class Site {
'$delivery_interval' => array('delivery_interval', t("Delivery interval"), (x(get_config('system','delivery_interval'))?get_config('system','delivery_interval'):2), t("Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers.")),
'$delivery_batch_count' => array('delivery_batch_count', t('Deliveries per process'),(x(get_config('system','delivery_batch_count'))?get_config('system','delivery_batch_count'):1), t("Number of deliveries to attempt in a single operating system process. Adjust if necessary to tune system performance. Recommend: 1-5.")),
'$poll_interval' => array('poll_interval', t("Poll interval"), (x(get_config('system','poll_interval'))?get_config('system','poll_interval'):2), t("Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval.")),
+ '$imagick_path' => array('imagick_path', t("Path to ImageMagick convert program"), get_config('system','imagick_convert_path'), t("If set, use this program to generate photo thumbnails for huge images ( > 4000 pixels in either dimension), otherwise memory exhaustion may occur. Example: /usr/bin/convert")),
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
'$form_security_token' => get_form_security_token("admin_site"),
diff --git a/Zotlabs/Module/Ap_probe.php b/Zotlabs/Module/Ap_probe.php
deleted file mode 100644
index 769cd4c4e..000000000
--- a/Zotlabs/Module/Ap_probe.php
+++ /dev/null
@@ -1,38 +0,0 @@
-<?php
-namespace Zotlabs\Module;
-
-require_once('include/zot.php');
-
-
-class Ap_probe extends \Zotlabs\Web\Controller {
-
- function get() {
-
- $o .= '<h3>ActivityPub Probe Diagnostic</h3>';
-
- $o .= '<form action="ap_probe" method="get">';
- $o .= 'Lookup URI: <input type="text" style="width: 250px;" name="addr" value="' . $_GET['addr'] .'" /><br>';
- $o .= 'Request Signed version: <input type=checkbox name="magenv" value="1" ><br>';
- $o .= '<input type="submit" name="submit" value="Submit" /></form>';
-
- $o .= '<br /><br />';
-
- if(x($_GET,'addr')) {
- $addr = $_GET['addr'];
-
- if($_GET['magenv']) {
- $headers = 'Accept: application/magic-envelope+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
- }
- else {
- $headers = 'Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
- }
-
- $redirects = 0;
- $x = z_fetch_url($addr,true,$redirects, [ 'headers' => [ $headers ]]);
- if($x['success'])
- $o .= '<pre>' . str_replace(['\\n','\\'],["\n",''],jindent($x['body'])) . '</pre>';
- }
- return $o;
- }
-
-}
diff --git a/Zotlabs/Module/Apporder.php b/Zotlabs/Module/Apporder.php
index 1097a01eb..956548d1f 100644
--- a/Zotlabs/Module/Apporder.php
+++ b/Zotlabs/Module/Apporder.php
@@ -11,30 +11,35 @@ class Apporder extends \Zotlabs\Web\Controller {
}
function get() {
- $syslist = array();
- $list = Zlib\Apps::app_list(local_channel(), false, 'nav_featured_app');
- if($list) {
- foreach($list as $li) {
- $syslist[] = Zlib\Apps::app_encode($li);
- }
- }
- Zlib\Apps::translate_system_apps($syslist);
- usort($syslist,'Zotlabs\\Lib\\Apps::app_name_compare');
+ if(! local_channel())
+ return;
- $syslist = Zlib\Apps::app_order(local_channel(),$syslist);
+ nav_set_selected('Order Apps');
- foreach($syslist as $app) {
- $nav_apps[] = Zlib\Apps::app_render($app,'nav-order');
+ $syslist = array();
+ $list = Zlib\Apps::app_list(local_channel(), false, 'nav_featured_app');
+ if($list) {
+ foreach($list as $li) {
+ $syslist[] = Zlib\Apps::app_encode($li);
+ }
+ }
+ Zlib\Apps::translate_system_apps($syslist);
+
+ usort($syslist,'Zotlabs\\Lib\\Apps::app_name_compare');
+
+ $syslist = Zlib\Apps::app_order(local_channel(),$syslist);
+ foreach($syslist as $app) {
+ $nav_apps[] = Zlib\Apps::app_render($app,'nav-order');
}
- return replace_macros(get_markup_template('apporder.tpl'),
- [
- '$header' => t('Change Order of Navigation Apps'),
- '$desc' => t('Use arrows to move the corresponding app up or down in the display list'),
- '$nav_apps' => $nav_apps
- ]
- );
+ return replace_macros(get_markup_template('apporder.tpl'),
+ [
+ '$header' => t('Change Order of Navigation Apps'),
+ '$desc' => t('Use arrows to move the corresponding app up or down in the display list'),
+ '$nav_apps' => $nav_apps
+ ]
+ );
}
}
diff --git a/Zotlabs/Module/Apps.php b/Zotlabs/Module/Apps.php
index 261615997..2f61f2932 100644
--- a/Zotlabs/Module/Apps.php
+++ b/Zotlabs/Module/Apps.php
@@ -7,6 +7,8 @@ use \Zotlabs\Lib as Zlib;
class Apps extends \Zotlabs\Web\Controller {
function get() {
+
+ nav_set_selected('Apps');
if(argc() == 2 && argv(1) == 'edit')
$mode = 'edit';
diff --git a/Zotlabs/Module/Attach.php b/Zotlabs/Module/Attach.php
index 94f46978a..490d5edd0 100644
--- a/Zotlabs/Module/Attach.php
+++ b/Zotlabs/Module/Attach.php
@@ -31,7 +31,7 @@ class Attach extends \Zotlabs\Web\Controller {
$unsafe_types = array('text/html','text/css','application/javascript');
- if(in_array($r['data']['filetype'],$unsafe_types)) {
+ if(in_array($r['data']['filetype'],$unsafe_types) && (! channel_codeallowed($r['data']['uid']))) {
header('Content-type: text/plain');
}
else {
diff --git a/Zotlabs/Module/Bookmarks.php b/Zotlabs/Module/Bookmarks.php
index e62f5ce96..e147ffe6c 100644
--- a/Zotlabs/Module/Bookmarks.php
+++ b/Zotlabs/Module/Bookmarks.php
@@ -8,7 +8,7 @@ class Bookmarks extends \Zotlabs\Web\Controller {
if(! local_channel())
return;
- nav_set_selected(t('View Bookmarks'));
+ nav_set_selected('View Bookmarks');
$item_id = intval($_REQUEST['item']);
$burl = trim($_REQUEST['burl']);
diff --git a/Zotlabs/Module/Card_edit.php b/Zotlabs/Module/Card_edit.php
new file mode 100644
index 000000000..7cc563fd2
--- /dev/null
+++ b/Zotlabs/Module/Card_edit.php
@@ -0,0 +1,138 @@
+<?php
+namespace Zotlabs\Module;
+
+require_once('include/channel.php');
+require_once('include/acl_selectors.php');
+require_once('include/conversation.php');
+
+class Card_edit extends \Zotlabs\Web\Controller {
+
+
+ function get() {
+
+ // Figure out which post we're editing
+ $post_id = ((argc() > 1) ? intval(argv(1)) : 0);
+
+ if(! $post_id) {
+ notice( t('Item not found') . EOL);
+ return;
+ }
+
+ $itm = q("SELECT * FROM item WHERE id = %d and item_type = %d LIMIT 1",
+ intval($post_id),
+ intval(ITEM_TYPE_CARD)
+ );
+ if($itm) {
+ $item_id = q("select * from iconfig where cat = 'system' and k = 'CARD' and iid = %d limit 1",
+ intval($itm[0]['id'])
+ );
+ if($item_id)
+ $card_title = $item_id[0]['v'];
+ }
+ else {
+ notice( t('Item not found') . EOL);
+ return;
+ }
+
+ $owner = $itm[0]['uid'];
+ $uid = local_channel();
+
+ $observer = \App::get_observer();
+
+ $channel = channelx_by_n($owner);
+ if(! $channel) {
+ notice( t('Channel not found.') . EOL);
+ return;
+ }
+
+ $ob_hash = (($observer) ? $observer['xchan_hash'] : '');
+
+ if(! perm_is_allowed($owner,$ob_hash,'write_pages')) {
+ notice( t('Permission denied.') . EOL);
+ return;
+ }
+
+ $is_owner = (($uid && $uid == $owner) ? true : false);
+
+ $o = '';
+
+
+
+ $category = '';
+ $catsenabled = ((feature_enabled($owner,'categories')) ? 'categories' : '');
+
+ if ($catsenabled){
+ $itm = fetch_post_tags($itm);
+
+ $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY);
+
+ foreach ($cats as $cat) {
+ if (strlen($category))
+ $category .= ', ';
+ $category .= $cat['term'];
+ }
+ }
+
+ if($itm[0]['attach']) {
+ $j = json_decode($itm[0]['attach'],true);
+ if($j) {
+ foreach($j as $jj) {
+ $itm[0]['body'] .= "\n" . '[attachment]' . basename($jj['href']) . ',' . $jj['revision'] . '[/attachment]' . "\n";
+ }
+ }
+ }
+
+
+ $mimetype = $itm[0]['mimetype'];
+
+ $content = $itm[0]['body'];
+
+
+
+ $rp = 'cards/' . $channel['channel_address'];
+
+ $x = array(
+ 'nickname' => $channel['channel_address'],
+ 'bbco_autocomplete'=> 'bbcode',
+ 'return_path' => $rp,
+ 'webpage' => ITEM_TYPE_CARD,
+ 'button' => t('Edit'),
+ 'writefiles' => perm_is_allowed($owner, get_observer_hash(), 'write_pages'),
+ 'weblink' => t('Insert web link'),
+ 'hide_voting' => false,
+ 'hide_future' => false,
+ 'hide_location' => false,
+ 'hide_expire' => false,
+ 'showacl' => true,
+ 'acl' => populate_acl($itm[0],false,\Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')),
+ 'permissions' => $itm[0],
+ 'lockstate' => (($itm[0]['allow_cid'] || $itm[0]['allow_gid'] || $itm[0]['deny_cid'] || $itm[0]['deny_gid']) ? 'lock' : 'unlock'),
+ 'ptyp' => $itm[0]['type'],
+ 'mimeselect' => false,
+ 'mimetype' => $itm[0]['mimetype'],
+ 'body' => undo_post_tagging($content),
+ 'post_id' => $post_id,
+ 'visitor' => true,
+ 'title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'),
+ 'placeholdertitle' => t('Title (optional)'),
+ 'pagetitle' => $card_title,
+ 'profile_uid' => (intval($channel['channel_id'])),
+ 'catsenabled' => $catsenabled,
+ 'category' => $category,
+ 'bbcode' => (($mimetype == 'text/bbcode') ? true : false)
+ );
+
+ $editor = status_editor($a, $x);
+
+ $o .= replace_macros(get_markup_template('edpost_head.tpl'), array(
+ '$title' => t('Edit Card'),
+ '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false),
+ '$id' => $itm[0]['id'],
+ '$editor' => $editor
+ ));
+
+ return $o;
+
+ }
+
+}
diff --git a/Zotlabs/Module/Cards.php b/Zotlabs/Module/Cards.php
new file mode 100644
index 000000000..22c5d673c
--- /dev/null
+++ b/Zotlabs/Module/Cards.php
@@ -0,0 +1,187 @@
+<?php
+namespace Zotlabs\Module;
+
+require_once('include/channel.php');
+require_once('include/conversation.php');
+require_once('include/acl_selectors.php');
+
+
+class Cards extends \Zotlabs\Web\Controller {
+
+ function init() {
+
+ if(argc() > 1)
+ $which = argv(1);
+ else
+ return;
+
+ profile_load($which);
+
+ }
+
+ function get($update = 0, $load = false) {
+
+ if(observer_prohibited(true)) {
+ return login();
+ }
+
+ if(! \App::$profile) {
+ notice( t('Requested profile is not available.') . EOL );
+ \App::$error = 404;
+ return;
+ }
+
+ if(! feature_enabled(\App::$profile_uid,'cards')) {
+ return;
+ }
+
+ nav_set_selected(t('Cards'));
+
+ head_add_link([
+ 'rel' => 'alternate',
+ 'type' => 'application/json+oembed',
+ 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string),
+ 'title' => 'oembed'
+ ]);
+
+
+ $category = (($_REQUEST['cat']) ? escape_tags(trim($_REQUEST['cat'])) : '');
+
+ if($category) {
+ $sql_extra2 .= protect_sprintf(term_item_parent_query(\App::$profile['profile_uid'],'item', $category, TERM_CATEGORY));
+ }
+
+
+ $which = argv(1);
+
+ $selected_card = ((argc() > 2) ? argv(2) : '');
+
+ $_SESSION['return_url'] = \App::$query_string;
+
+ $uid = local_channel();
+ $owner = \App::$profile_uid;
+ $observer = \App::get_observer();
+
+ $ob_hash = (($observer) ? $observer['xchan_hash'] : '');
+
+ if(! perm_is_allowed($owner,$ob_hash,'view_pages')) {
+ notice( t('Permission denied.') . EOL);
+ return;
+ }
+
+ $is_owner = ($uid && $uid == $owner);
+
+ $channel = channelx_by_n($owner);
+
+ if($channel) {
+ $channel_acl = array(
+ 'allow_cid' => $channel['channel_allow_cid'],
+ 'allow_gid' => $channel['channel_allow_gid'],
+ 'deny_cid' => $channel['channel_deny_cid'],
+ 'deny_gid' => $channel['channel_deny_gid']
+ );
+ }
+ else {
+ $channel_acl = [ 'allow_cid' => '', 'allow_gid' => '', 'deny_cid' => '', 'deny_gid' => '' ];
+ }
+
+
+
+ if(perm_is_allowed($owner,$ob_hash,'write_pages')) {
+
+ $x = [
+ 'webpage' => ITEM_TYPE_CARD,
+ 'is_owner' => true,
+ 'content_label' => t('Add Card'),
+ 'button' => t('Create'),
+ 'nickname' => $channel['channel_address'],
+ 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid']
+ || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'),
+ 'acl' => (($is_owner) ? populate_acl($channel_acl, false,
+ \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_pages')) : ''),
+ 'permissions' => $channel_acl,
+ 'showacl' => (($is_owner) ? true : false),
+ 'visitor' => true,
+ 'hide_location' => false,
+ 'hide_voting' => false,
+ 'profile_uid' => intval($owner),
+ 'mimetype' => 'text/bbcode',
+ 'mimeselect' => false,
+ 'layoutselect' => false,
+ 'expanded' => false,
+ 'novoting' => false,
+ 'catsenabled' => feature_enabled($owner,'categories'),
+ 'bbco_autocomplete' => 'bbcode',
+ 'bbcode' => true
+ ];
+
+ if($_REQUEST['title'])
+ $x['title'] = $_REQUEST['title'];
+ if($_REQUEST['body'])
+ $x['body'] = $_REQUEST['body'];
+ $editor = status_editor($a,$x);
+
+ }
+ else {
+ $editor = '';
+ }
+
+
+ $sql_extra = item_permissions_sql($owner);
+
+ if($selected_card) {
+ $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.v = '%s' limit 1",
+ dbesc($selected_card)
+ );
+ if($r) {
+ $sql_extra .= "and item.id = " . intval($r[0]['iid']) . " ";
+ }
+ }
+
+ $r = q("select * from item
+ where item.uid = %d and item_type = %d
+ $sql_extra order by item.created desc",
+ intval($owner),
+ intval(ITEM_TYPE_CARD)
+ );
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type in (0,6) and item.item_deleted = 0
+ and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 ";
+
+ if($r) {
+
+ $parents_str = ids_to_querystr($r,'id');
+
+ $items = q("SELECT item.*, item.id AS item_id
+ FROM item
+ WHERE item.uid = %d $item_normal
+ AND item.parent IN ( %s )
+ $sql_extra $sql_extra2 ",
+ intval(\App::$profile['profile_uid']),
+ dbesc($parents_str)
+ );
+ if($items) {
+ xchan_query($items);
+ $items = fetch_post_tags($items, true);
+ $items = conv_sort($items,'updated');
+ }
+ else
+ $items = [];
+ }
+
+ $mode = 'cards';
+
+ $content = conversation($items,$mode,false,'traditional');
+
+ $o = replace_macros(get_markup_template('cards.tpl'), [
+ '$title' => t('Cards'),
+ '$editor' => $editor,
+ '$content' => $content,
+ '$pager' => alt_pager($a,count($items))
+ ]);
+
+ return $o;
+ }
+
+}
diff --git a/Zotlabs/Module/Cdav.php b/Zotlabs/Module/Cdav.php
index d0619ef0b..77052f97c 100644
--- a/Zotlabs/Module/Cdav.php
+++ b/Zotlabs/Module/Cdav.php
@@ -3,31 +3,81 @@ namespace Zotlabs\Module;
require_once('include/event.php');
+require_once('include/auth.php');
+require_once('include/security.php');
+
class Cdav extends \Zotlabs\Web\Controller {
function init() {
+ $record = null;
+ $channel_login = false;
+
if((argv(1) !== 'calendar') && (argv(1) !== 'addressbook')) {
- // workaround for HTTP-auth in CGI mode
- if (x($_SERVER, 'REDIRECT_REMOTE_USER')) {
- $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ;
- if(strlen($userpass)) {
- list($name, $password) = explode(':', $userpass);
- $_SERVER['PHP_AUTH_USER'] = $name;
- $_SERVER['PHP_AUTH_PW'] = $password;
+ foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) {
+
+ /* Basic authentication */
+
+ if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,5) === 'Basic') {
+ $userpass = @base64_decode(substr(trim($_SERVER[$head]),6)) ;
+ if(strlen($userpass)) {
+ list($name, $password) = explode(':', $userpass);
+ $_SERVER['PHP_AUTH_USER'] = $name;
+ $_SERVER['PHP_AUTH_PW'] = $password;
+ }
+ break;
}
- }
- if (x($_SERVER, 'HTTP_AUTHORIZATION')) {
- $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ;
- if(strlen($userpass)) {
- list($name, $password) = explode(':', $userpass);
- $_SERVER['PHP_AUTH_USER'] = $name;
- $_SERVER['PHP_AUTH_PW'] = $password;
+ /* Signature authentication */
+
+ if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') {
+ if($head !== 'HTTP_AUTHORIZATION') {
+ $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head];
+ continue;
+ }
+
+ $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
+ if($sigblock) {
+ $keyId = $sigblock['keyId'];
+ if($keyId) {
+ $r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
+ dbesc($keyId)
+ );
+ if($r) {
+ $c = channelx_by_hash($r[0]['hubloc_hash']);
+ if($c) {
+ $a = q("select * from account where account_id = %d limit 1",
+ intval($c['channel_account_id'])
+ );
+ if($a) {
+ $record = [ 'channel' => $c, 'account' => $a[0] ];
+ $channel_login = $c['channel_id'];
+ }
+ }
+ }
+ if(! $record)
+ continue;
+
+ if($record) {
+ $verified = \Zotlabs\Web\HTTPSig::verify('',$record['channel']['channel_pubkey']);
+ if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
+ $record = null;
+ }
+ if($record['account']) {
+ authenticate_success($record['account']);
+ if($channel_login) {
+ change_channel($channel_login);
+ }
+ }
+ break;
+ }
+ }
+ }
}
}
+
/**
* This server combines both CardDAV and CalDAV functionality into a single
* server. It is assumed that the server runs at the root of a HTTP domain (be
@@ -774,7 +824,7 @@ class Cdav extends \Zotlabs\Web\Controller {
}
if(argv(1) === 'calendar') {
- nav_set_selected(t('CalDAV'));
+ nav_set_selected('CalDAV');
$caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
$calendars = $caldavBackend->getCalendarsForUser($principalUri);
}
@@ -975,7 +1025,7 @@ class Cdav extends \Zotlabs\Web\Controller {
if(argv(1) === 'addressbook') {
- nav_set_selected(t('CardDAV'));
+ nav_set_selected('CardDAV');
$carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo);
$addressbooks = $carddavBackend->getAddressBooksForUser($principalUri);
}
diff --git a/Zotlabs/Module/Changeaddr.php b/Zotlabs/Module/Changeaddr.php
new file mode 100644
index 000000000..5cd236394
--- /dev/null
+++ b/Zotlabs/Module/Changeaddr.php
@@ -0,0 +1,88 @@
+<?php
+namespace Zotlabs\Module;
+
+
+class Changeaddr extends \Zotlabs\Web\Controller {
+
+ function post() {
+
+ if(! local_channel())
+ return;
+
+ if($_SESSION['delegate'])
+ return;
+
+ if((! x($_POST,'qxz_password')) || (! strlen(trim($_POST['qxz_password']))))
+ return;
+
+ if((! x($_POST,'verify')) || (! strlen(trim($_POST['verify']))))
+ return;
+
+ if($_POST['verify'] !== $_SESSION['remove_account_verify'])
+ return;
+
+
+ $account = \App::get_account();
+ $channel = \App::get_channel();
+
+ $x = account_verify_password($account['account_email'],$_POST['qxz_password']);
+ if(! ($x && $x['account']))
+ return;
+
+ if($account['account_password_changed'] > NULL_DATE) {
+ $d1 = datetime_convert('UTC','UTC','now - 48 hours');
+ if($account['account_password_changed'] > d1) {
+ notice( t('Channel name changes are not allowed within 48 hours of changing the account password.') . EOL);
+ return;
+ }
+ }
+
+ $new_address = trim($_POST['newname']);
+
+ if($new_address === $channel['channel_address'])
+ return;
+
+ if($new_address === 'sys') {
+ notice( t('Reserved nickname. Please choose another.') . EOL);
+ return;
+ }
+
+ if(check_webbie(array($new_address)) !== $new_address) {
+ notice( t('Nickname has unsupported characters or is already being used on this site.') . EOL);
+ return $ret;
+ }
+
+ channel_change_address($channel,$new_address);
+
+ goaway(z_root() . '/changeaddr');
+
+ }
+
+
+ function get() {
+
+ if(! local_channel())
+ goaway(z_root());
+
+ $channel = \App::get_channel();
+
+ $hash = random_string();
+
+ $_SESSION['remove_account_verify'] = $hash;
+
+ $tpl = get_markup_template('channel_rename.tpl');
+ $o .= replace_macros($tpl, array(
+ '$basedir' => z_root(),
+ '$hash' => $hash,
+ '$title' => t('Change channel nickname/address'),
+ '$desc' => array(t('WARNING: '), t('Any/all connections on other networks will be lost!')),
+ '$passwd' => t('Please enter your password for verification:'),
+ '$newname' => array('newname', t('New channel address'),$channel['channel_address'], ''),
+ '$submit' => t('Rename Channel')
+ ));
+
+ return $o;
+
+ }
+
+}
diff --git a/Zotlabs/Module/Channel.php b/Zotlabs/Module/Channel.php
index a44984c97..14d02d873 100644
--- a/Zotlabs/Module/Channel.php
+++ b/Zotlabs/Module/Channel.php
@@ -92,11 +92,6 @@ class Channel extends \Zotlabs\Web\Controller {
// Ensure we've got a profile owner if updating.
\App::$profile['profile_uid'] = \App::$profile_uid = $update;
}
- else {
- if(\App::$profile['profile_uid'] == local_channel()) {
- nav_set_selected(t('Channel Home'));
- }
- }
$is_owner = (((local_channel()) && (\App::$profile['profile_uid'] == local_channel())) ? true : false);
@@ -119,11 +114,13 @@ class Channel extends \Zotlabs\Web\Controller {
if(! $update) {
+ nav_set_selected('Channel Home');
+
$static = channel_manual_conv_update(\App::$profile['profile_uid']);
//$o .= profile_tabs($a, $is_owner, \App::$profile['channel_address']);
- $o .= common_friends_visitor_widget(\App::$profile['profile_uid']);
+ // $o .= common_friends_visitor_widget(\App::$profile['profile_uid']);
if($channel && $is_owner) {
$channel_acl = array(
@@ -169,6 +166,7 @@ class Channel extends \Zotlabs\Web\Controller {
*/
$item_normal = item_normal();
+ $item_normal_update = item_normal_update();
$sql_extra = item_permissions_sql(\App::$profile['profile_uid']);
if(get_pconfig(\App::$profile['profile_uid'],'system','channel_list_mode') && (! $mid))
@@ -180,7 +178,12 @@ class Channel extends \Zotlabs\Web\Controller {
$simple_update = (($update) ? " AND item_unseen = 1 " : '');
- \App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string) . '" title="oembed" />' . "\r\n";
+ head_add_link([
+ 'rel' => 'alternate',
+ 'type' => 'application/json+oembed',
+ 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string),
+ 'title' => 'oembed'
+ ]);
if($update && $_SESSION['loadtime'])
$simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
@@ -188,12 +191,12 @@ class Channel extends \Zotlabs\Web\Controller {
$simple_update = '';
if($static && $simple_update)
- $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
+ $simple_update .= " and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
if(($update) && (! $load)) {
if($mid) {
- $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal
+ $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal_update
AND item_wall = 1 $simple_update $sql_extra limit 1",
dbesc($mid . '%'),
intval(\App::$profile['profile_uid'])
@@ -203,7 +206,7 @@ class Channel extends \Zotlabs\Web\Controller {
else {
$r = q("SELECT distinct parent AS item_id, created from item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
- WHERE uid = %d $item_normal
+ WHERE uid = %d $item_normal_update
AND item_wall = 1 $simple_update
AND (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra
@@ -236,7 +239,7 @@ class Channel extends \Zotlabs\Web\Controller {
if($load || ($checkjs->disabled())) {
if($mid) {
- $r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal
+ $r = q("SELECT distinct parent AS item_id from item where mid like '%s' and uid = %d $item_normal
AND item_wall = 1 $sql_extra limit 1",
dbesc($mid . '%'),
intval(\App::$profile['profile_uid'])
@@ -358,9 +361,13 @@ class Channel extends \Zotlabs\Web\Controller {
}
if($is_owner && $update_unseen) {
- $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen",
- intval(local_channel())
- );
+ $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ];
+ call_hooks('update_unseen',$x);
+ if($x['update'] === 'unset' || intval($x['update'])) {
+ $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen",
+ intval(local_channel())
+ );
+ }
}
diff --git a/Zotlabs/Module/Chat.php b/Zotlabs/Module/Chat.php
index 138ca1cb5..378c9f4dd 100644
--- a/Zotlabs/Module/Chat.php
+++ b/Zotlabs/Module/Chat.php
@@ -91,7 +91,7 @@ class Chat extends \Zotlabs\Web\Controller {
if(local_channel()) {
$channel = \App::get_channel();
- nav_set_selected(t('My Chatrooms'));
+ nav_set_selected('My Chatrooms');
}
$ob = \App::get_observer();
diff --git a/Zotlabs/Module/Common.php b/Zotlabs/Module/Common.php
index 2f3c57267..eebc56d2b 100644
--- a/Zotlabs/Module/Common.php
+++ b/Zotlabs/Module/Common.php
@@ -25,7 +25,7 @@ class Common extends \Zotlabs\Web\Controller {
}
- function get() {
+ function get() {
$o = '';
@@ -34,38 +34,37 @@ class Common extends \Zotlabs\Web\Controller {
$observer_hash = get_observer_hash();
-
if(! perm_is_allowed(\App::$profile['profile_uid'],$observer_hash,'view_contacts')) {
notice( t('Permission denied.') . EOL);
return;
}
- $o .= '<h2>' . t('Common connections') . '</h2>';
-
$t = count_common_friends(\App::$profile['profile_uid'],$observer_hash);
if(! $t) {
notice( t('No connections in common.') . EOL);
- return $o;
+ return;
}
$r = common_friends(\App::$profile['profile_uid'],$observer_hash);
if($r) {
-
- $tpl = get_markup_template('common_friends.tpl');
-
foreach($r as $rr) {
- $o .= replace_macros($tpl,array(
- '$url' => $rr['xchan_url'],
- '$name' => $rr['xchan_name'],
- '$photo' => $rr['xchan_photo_m'],
- '$tags' => ''
- ));
+ $items[] = [
+ 'url' => $rr['xchan_url'],
+ 'name' => $rr['xchan_name'],
+ 'photo' => $rr['xchan_photo_m'],
+ 'tags' => ''
+ ];
}
-
- $o .= cleardiv();
}
+
+ $tpl = get_markup_template('common_friends.tpl');
+
+ $o = replace_macros($tpl, [
+ '$title' => t('View Common Connections'),
+ '$items' => $items
+ ]);
return $o;
}
diff --git a/Zotlabs/Module/Connections.php b/Zotlabs/Module/Connections.php
index 6ad1e9528..f42ff9b84 100644
--- a/Zotlabs/Module/Connections.php
+++ b/Zotlabs/Module/Connections.php
@@ -30,7 +30,7 @@ class Connections extends \Zotlabs\Web\Controller {
return login();
}
- nav_set_selected(t('Connections'));
+ nav_set_selected('Connections');
$blocked = false;
$hidden = false;
diff --git a/Zotlabs/Module/Connedit.php b/Zotlabs/Module/Connedit.php
index d301c2d45..23c5282e3 100644
--- a/Zotlabs/Module/Connedit.php
+++ b/Zotlabs/Module/Connedit.php
@@ -248,6 +248,10 @@ class Connedit extends \Zotlabs\Web\Controller {
notice( t('Failed to update connection record.') . EOL);
if(! intval(\App::$poi['abook_self'])) {
+ if($new_friend) {
+ \Zotlabs\Daemon\Master::Summon( [ 'Notifier', 'permission_accept', $contact_id ] );
+ }
+
\Zotlabs\Daemon\Master::Summon( [
'Notifier',
(($new_friend) ? 'permission_create' : 'permission_update'),
@@ -841,7 +845,7 @@ class Connedit extends \Zotlabs\Web\Controller {
}
}
else
- $locstr = t('none');
+ $locstr = $contact['xchan_url'];
$clone_warn = '';
$clonable = (in_array($contact['xchan_network'],['zot','rss']) ? true : false);
@@ -866,6 +870,7 @@ class Connedit extends \Zotlabs\Web\Controller {
'$permcat_new' => t('Add permission role'),
'$permcat_enable' => feature_enabled(local_channel(),'permcats'),
'$addr' => $contact['xchan_addr'],
+ '$primeurl' => $contact['xchan_url'],
'$section' => $section,
'$sections' => $sections,
'$vcard' => $vcard,
diff --git a/Zotlabs/Module/Dav.php b/Zotlabs/Module/Dav.php
index 8ae2e8991..d506fe9f5 100644
--- a/Zotlabs/Module/Dav.php
+++ b/Zotlabs/Module/Dav.php
@@ -12,6 +12,9 @@ use \Sabre\DAV as SDAV;
use \Zotlabs\Storage;
require_once('include/attach.php');
+require_once('include/auth.php');
+require_once('include/security.php');
+
class Dav extends \Zotlabs\Web\Controller {
@@ -21,22 +24,65 @@ class Dav extends \Zotlabs\Web\Controller {
*/
function init() {
- // workaround for HTTP-auth in CGI mode
- if (x($_SERVER, 'REDIRECT_REMOTE_USER')) {
- $userpass = base64_decode(substr($_SERVER["REDIRECT_REMOTE_USER"], 6)) ;
- if(strlen($userpass)) {
- list($name, $password) = explode(':', $userpass);
- $_SERVER['PHP_AUTH_USER'] = $name;
- $_SERVER['PHP_AUTH_PW'] = $password;
+ foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) {
+
+ /* Basic authentication */
+
+ if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,5) === 'Basic') {
+ $userpass = @base64_decode(substr(trim($_SERVER[$head]),6)) ;
+ if(strlen($userpass)) {
+ list($name, $password) = explode(':', $userpass);
+ $_SERVER['PHP_AUTH_USER'] = $name;
+ $_SERVER['PHP_AUTH_PW'] = $password;
+ }
+ break;
}
- }
- if (x($_SERVER, 'HTTP_AUTHORIZATION')) {
- $userpass = base64_decode(substr($_SERVER["HTTP_AUTHORIZATION"], 6)) ;
- if(strlen($userpass)) {
- list($name, $password) = explode(':', $userpass);
- $_SERVER['PHP_AUTH_USER'] = $name;
- $_SERVER['PHP_AUTH_PW'] = $password;
+ /* Signature authentication */
+
+ if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') {
+ if($head !== 'HTTP_AUTHORIZATION') {
+ $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head];
+ continue;
+ }
+
+ $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
+ if($sigblock) {
+ $keyId = $sigblock['keyId'];
+ if($keyId) {
+ $r = q("select * from hubloc where hubloc_addr = '%s' limit 1",
+ dbesc($keyId)
+ );
+ if($r) {
+ $c = channelx_by_hash($r[0]['hubloc_hash']);
+ if($c) {
+ $a = q("select * from account where account_id = %d limit 1",
+ intval($c['channel_account_id'])
+ );
+ if($a) {
+ $record = [ 'channel' => $c, 'account' => $a[0] ];
+ $channel_login = $c['channel_id'];
+ }
+ }
+ }
+ if(! $record)
+ continue;
+
+ if($record) {
+ $verified = \Zotlabs\Web\HTTPSig::verify('',$record['channel']['channel_pubkey']);
+ if(! ($verified && $verified['header_signed'] && $verified['header_valid'])) {
+ $record = null;
+ }
+ if($record['account']) {
+ authenticate_success($record['account']);
+ if($channel_login) {
+ change_channel($channel_login);
+ }
+ }
+ break;
+ }
+ }
+ }
}
}
diff --git a/Zotlabs/Module/Directory.php b/Zotlabs/Module/Directory.php
index 6268e99c6..caf0190ae 100644
--- a/Zotlabs/Module/Directory.php
+++ b/Zotlabs/Module/Directory.php
@@ -77,7 +77,7 @@ class Directory extends \Zotlabs\Web\Controller {
$pubforums = get_directory_setting($observer, 'pubforums');
$o = '';
- nav_set_selected(t('Directory'));
+ nav_set_selected('Directory');
if(x($_POST,'search'))
$search = notags(trim($_POST['search']));
diff --git a/Zotlabs/Module/Display.php b/Zotlabs/Module/Display.php
index df3cb1e2b..d5afdd787 100644
--- a/Zotlabs/Module/Display.php
+++ b/Zotlabs/Module/Display.php
@@ -17,20 +17,18 @@ class Display extends \Zotlabs\Web\Controller {
if($load)
$_SESSION['loadtime'] = datetime_convert();
-
if(observer_prohibited()) {
notice( t('Public access denied.') . EOL);
return;
}
-
if(argc() > 1 && argv(1) !== 'load')
$item_hash = argv(1);
if($_REQUEST['mid'])
$item_hash = $_REQUEST['mid'];
- if(! $item_hash) {
+ if(! $item_hash) {
\App::$error = 404;
notice( t('Item not found.') . EOL);
return;
@@ -38,21 +36,18 @@ class Display extends \Zotlabs\Web\Controller {
$observer_is_owner = false;
$updateable = false;
-
-
+
if(local_channel() && (! $update)) {
$channel = \App::get_channel();
-
-
+
$channel_acl = array(
'allow_cid' => $channel['channel_allow_cid'],
'allow_gid' => $channel['channel_allow_gid'],
'deny_cid' => $channel['channel_deny_cid'],
'deny_gid' => $channel['channel_deny_gid']
);
-
-
+
$x = array(
'is_owner' => true,
'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''),
@@ -76,7 +71,6 @@ class Display extends \Zotlabs\Web\Controller {
$o = '<div id="jot-popup">';
$o .= status_editor($a,$x);
$o .= '</div>';
-
}
// This page can be viewed by anybody so the query could be complicated
@@ -95,14 +89,18 @@ class Display extends \Zotlabs\Web\Controller {
if($decoded)
$item_hash = $decoded;
- $r = q("select id, uid, mid, parent_mid, item_type, item_deleted from item where mid like '%s' limit 1",
- dbesc($item_hash . '%'),
- dbesc($decoded . '%')
+ $r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where mid like '%s' limit 1",
+ dbesc($item_hash . '%')
);
if($r) {
$target_item = $r[0];
}
+
+ //if the item is to be moderated redirect to /moderate
+ if($target_item['item_blocked'] == ITEM_MODERATED) {
+ goaway(z_root() . '/moderate/' . $target_item['id']);
+ }
$r = null;
@@ -138,10 +136,16 @@ class Display extends \Zotlabs\Web\Controller {
$simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
if((! $update) && (! $load)) {
-
- $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 0);
-
+ $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1);
+
+ //if the target item is not a post (eg a like) we want to address its thread parent
+ $mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
+
+ //if we got a decoded hash we must encode it again before handing to javascript
+ if($decoded)
+ $mid = 'b64.' . base64url_encode($mid);
+
$o .= '<div id="live-display"></div>' . "\r\n";
$o .= "<script> var profile_uid = " . ((intval(local_channel())) ? local_channel() : (-1))
. "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . "; </script>\r\n";
@@ -173,25 +177,31 @@ class Display extends \Zotlabs\Web\Controller {
'$dend' => '',
'$dbegin' => '',
'$verb' => '',
- '$mid' => $item_hash
+ '$mid' => $mid
));
-
-
+
+ head_add_link([
+ 'rel' => 'alternate',
+ 'type' => 'application/json+oembed',
+ 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string),
+ 'title' => 'oembed'
+ ]);
+
}
-
+
$observer_hash = get_observer_hash();
$item_normal = item_normal();
-
+ $item_normal_update = item_normal_update();
+
$sql_extra = public_permissions_sql($observer_hash);
if(($update && $load) || ($checkjs->disabled())) {
-
-
+
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(\App::$pager['itemspage']),intval(\App::$pager['start']));
-
+
if($load || ($checkjs->disabled())) {
$r = null;
-
+
require_once('include/channel.php');
$sys = get_sys_channel();
$sysid = $sys['channel_id'];
@@ -207,25 +217,22 @@ class Display extends \Zotlabs\Web\Controller {
);
if($r) {
$updateable = true;
-
}
-
}
if($r === null) {
-
+
// in case somebody turned off public access to sys channel content using permissions
- // make that content unsearchable by ensuring the owner_xchan can't match
-
+ // make that content unsearchable by ensuring the owner uid can't match
+
if(! perm_is_allowed($sysid,$observer_hash,'view_stream'))
$sysid = 0;
-
-
+
$r = q("SELECT item.id as item_id from item
WHERE mid = '%s'
AND (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = ''
AND item.deny_gid = '' AND item_private = 0 )
- and owner_xchan in ( " . stream_perms_xchans(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
+ and uid in ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
OR uid = %d )
$sql_extra )
$item_normal
@@ -233,7 +240,6 @@ class Display extends \Zotlabs\Web\Controller {
dbesc($target_item['parent_mid']),
intval($sysid)
);
-
}
}
}
@@ -249,7 +255,7 @@ class Display extends \Zotlabs\Web\Controller {
$r = q("SELECT item.parent AS item_id from item
WHERE uid = %d
and parent_mid = '%s'
- $item_normal
+ $item_normal_update
$simple_update
limit 1",
intval(local_channel()),
@@ -265,15 +271,15 @@ class Display extends \Zotlabs\Web\Controller {
// make that content unsearchable by ensuring the owner_xchan can't match
if(! perm_is_allowed($sysid,$observer_hash,'view_stream'))
$sysid = 0;
-
+
$r = q("SELECT item.parent AS item_id from item
WHERE parent_mid = '%s'
AND (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = ''
AND item.deny_gid = '' AND item_private = 0 )
- and owner_xchan in ( " . stream_perms_xchans(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
+ and uid in ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
OR uid = %d )
$sql_extra )
- $item_normal
+ $item_normal_update
$simple_update
limit 1",
dbesc($target_item['parent_mid']),
@@ -288,10 +294,8 @@ class Display extends \Zotlabs\Web\Controller {
}
if($r) {
-
$parents_str = ids_to_querystr($r,'item_id');
if($parents_str) {
-
$items = q("SELECT item.*, item.id AS item_id
FROM item
WHERE parent in ( %s ) $item_normal ",
@@ -302,11 +306,11 @@ class Display extends \Zotlabs\Web\Controller {
$items = fetch_post_tags($items,true);
$items = conv_sort($items,'created');
}
- } else {
+ }
+ else {
$items = array();
}
-
if ($checkjs->disabled()) {
$o .= conversation($items, 'display', $update, 'traditional');
if ($items[0]['title'])
@@ -324,17 +328,13 @@ class Display extends \Zotlabs\Web\Controller {
}
$o .= '<div id="content-complete"></div>';
-
- return $o;
-
-
- /*
- elseif((! $update) && (! {
+
+ if((($update && $load) || $checkjs->disabled()) && (! $items)) {
- $r = q("SELECT id, item_flags FROM item WHERE id = '%s' OR mid = '%s' LIMIT 1",
- dbesc($item_hash),
+ $r = q("SELECT id, item_deleted FROM item WHERE mid = '%s' LIMIT 1",
dbesc($item_hash)
);
+
if($r) {
if(intval($r[0]['item_deleted'])) {
notice( t('Item has been removed.') . EOL );
@@ -348,8 +348,9 @@ class Display extends \Zotlabs\Web\Controller {
}
}
- */
+
+ return $o;
+
}
-
-
+
}
diff --git a/Zotlabs/Module/Events.php b/Zotlabs/Module/Events.php
index 0541f5e9b..33c8b8249 100644
--- a/Zotlabs/Module/Events.php
+++ b/Zotlabs/Module/Events.php
@@ -272,7 +272,7 @@ class Events extends \Zotlabs\Web\Controller {
return;
}
- nav_set_selected(t('Events'));
+ nav_set_selected('Events');
if((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) {
$r = q("update event set dismissed = 1 where id = %d and uid = %d",
diff --git a/Zotlabs/Module/File_upload.php b/Zotlabs/Module/File_upload.php
index 29a7bd137..5c4b9a502 100644
--- a/Zotlabs/Module/File_upload.php
+++ b/Zotlabs/Module/File_upload.php
@@ -34,10 +34,26 @@ class File_upload extends \Zotlabs\Web\Controller {
$_REQUEST['deny_gid'] = perms2str($_REQUEST['group_deny']);
if($_REQUEST['filename']) {
- $r = attach_mkdir($channel,get_observer_hash(),$_REQUEST);
+ $r = attach_mkdir($channel, get_observer_hash(), $_REQUEST);
+ if($r['success']) {
+ $hash = $r['data']['hash'];
+
+ $sync = attach_export_data($channel,$hash);
+ if($sync) {
+ build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ }
+ goaway(z_root() . '/cloud/' . $channel['channel_address'] . '/' . $r['data']['display_path']);
+
+ }
}
else {
- $r = attach_store($channel,get_observer_hash(), '', $_REQUEST);
+ $r = attach_store($channel, get_observer_hash(), '', $_REQUEST);
+ if($r['success']) {
+ $sync = attach_export_data($channel,$r['data']['hash']);
+ if($sync)
+ build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+
+ }
}
goaway(z_root() . '/' . $_REQUEST['return_url']);
diff --git a/Zotlabs/Module/Filestorage.php b/Zotlabs/Module/Filestorage.php
index d6f363e77..55713027a 100644
--- a/Zotlabs/Module/Filestorage.php
+++ b/Zotlabs/Module/Filestorage.php
@@ -18,7 +18,7 @@ class Filestorage extends \Zotlabs\Web\Controller {
$recurse = ((x($_POST, 'recurse')) ? intval($_POST['recurse']) : 0);
$resource = ((x($_POST, 'filehash')) ? notags($_POST['filehash']) : '');
- $notify = ((x($_POST, 'notify')) ? intval($_POST['notify']) : 0);
+ $notify = ((x($_POST, 'notify_edit')) ? intval($_POST['notify_edit']) : 0);
if(! $resource) {
notice(t('Item not found.') . EOL);
@@ -31,16 +31,16 @@ class Filestorage extends \Zotlabs\Web\Controller {
$acl->set_from_array($_POST);
$x = $acl->get();
- $cloudPath = get_parent_cloudpath($channel_id, $channel['channel_address'], $resource);
+ $url = get_cloud_url($channel_id, $channel['channel_address'], $resource);
//get the object before permissions change so we can catch eventual former allowed members
- $object = get_file_activity_object($channel_id, $resource, $cloudPath);
+ $object = get_file_activity_object($channel_id, $resource, $url);
attach_change_permissions($channel_id, $resource, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], $recurse, true);
file_activity($channel_id, $object, $x['allow_cid'], $x['allow_gid'], $x['deny_cid'], $x['deny_gid'], 'post', $notify);
- goaway($cloudPath);
+ goaway(dirname($url));
}
function get() {
@@ -99,11 +99,11 @@ class Filestorage extends \Zotlabs\Web\Controller {
$f = $r[0];
$channel = \App::get_channel();
- $parentpath = get_parent_cloudpath($channel['channel_id'], $channel['channel_address'], $f['hash']);
+ $url = get_cloud_url($channel['channel_id'], $channel['channel_address'], $f['hash']);
attach_delete($owner, $f['hash']);
- goaway($parentpath);
+ goaway(dirname($url));
}
if(argc() > 3 && argv(3) === 'edit') {
@@ -123,7 +123,6 @@ class Filestorage extends \Zotlabs\Web\Controller {
$channel = \App::get_channel();
$cloudpath = get_cloudpath($f);
- $parentpath = get_parent_cloudpath($channel['channel_id'], $channel['channel_address'], $f['hash']);
$aclselect_e = populate_acl($f, false, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_storage'));
$is_a_dir = (intval($f['is_dir']) ? true : false);
@@ -138,7 +137,6 @@ class Filestorage extends \Zotlabs\Web\Controller {
'$header' => t('Edit file permissions'),
'$file' => $f,
'$cloudpath' => z_root() . '/' . $encoded_path,
- '$parentpath' => $parentpath,
'$uid' => $channel['channel_id'],
'$channelnick' => $channel['channel_address'],
'$permissions' => t('Permissions'),
@@ -157,7 +155,7 @@ class Filestorage extends \Zotlabs\Web\Controller {
'$submit' => t('Submit'),
'$attach_btn_title' => t('Share this file'),
'$link_btn_title' => t('Show URL to this file'),
- '$notify' => array('notify', t('Notify your contacts about this file'), 0, '', array(t('No'), t('Yes'))),
+ '$notify' => array('notify_edit', t('Show in your contacts shared folder'), 0, '', array(t('No'), t('Yes'))),
));
echo $o;
diff --git a/Zotlabs/Module/Getfile.php b/Zotlabs/Module/Getfile.php
index 0b05d78a4..413a68e0c 100644
--- a/Zotlabs/Module/Getfile.php
+++ b/Zotlabs/Module/Getfile.php
@@ -108,7 +108,7 @@ class Getfile extends \Zotlabs\Web\Controller {
$unsafe_types = array('text/html','text/css','application/javascript');
- if(in_array($r['data']['filetype'],$unsafe_types)) {
+ if(in_array($r['data']['filetype'],$unsafe_types) && (! channel_codeallowed($channel['channel_id']))) {
header('Content-type: text/plain');
}
else {
diff --git a/Zotlabs/Module/Help.php b/Zotlabs/Module/Help.php
index e98cb9d4d..f1b1acaef 100644
--- a/Zotlabs/Module/Help.php
+++ b/Zotlabs/Module/Help.php
@@ -15,7 +15,7 @@ require_once('include/help.php');
class Help extends \Zotlabs\Web\Controller {
function get() {
- nav_set_selected(t('Help'));
+ nav_set_selected('Help');
if($_REQUEST['search']) {
$o .= '<div id="help-content" class="generic-content-wrapper">';
@@ -88,12 +88,15 @@ class Help extends \Zotlabs\Web\Controller {
$heading = $headings[argv(1)];
$content = get_help_content();
+
+ $language = determine_help_language()['language'];
return replace_macros(get_markup_template('help.tpl'), array(
'$title' => t('$Projectname Documentation'),
'$tocHeading' => t('Contents'),
'$content' => $content,
- '$heading' => $heading
+ '$heading' => $heading,
+ '$language' => $language
));
}
diff --git a/Zotlabs/Module/Import.php b/Zotlabs/Module/Import.php
index 40ce8f6d1..2b16ff4e1 100644
--- a/Zotlabs/Module/Import.php
+++ b/Zotlabs/Module/Import.php
@@ -278,20 +278,31 @@ class Import extends \Zotlabs\Web\Controller {
create_table_from_array('xchan',$xchan);
require_once('include/photo/photo_driver.php');
- $photos = import_xchan_photo($xchan['xchan_photo_l'],$xchan['xchan_hash']);
- if($photos[4])
- $photodate = NULL_DATE;
- else
- $photodate = $xchan['xchan_photo_date'];
-
- $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s', xchan_photo_date = '%s' where xchan_hash = '%s'",
- dbesc($photos[0]),
- dbesc($photos[1]),
- dbesc($photos[2]),
- dbesc($photos[3]),
- dbesc($photodate),
- dbesc($xchan['xchan_hash'])
- );
+
+ if($xchan['xchan_hash'] === $channel['channel_hash']) {
+ $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s' where xchan_hash = '%s'",
+ dbesc(z_root() . '/photo/profile/l/' . $channel['channel_id']),
+ dbesc(z_root() . '/photo/profile/m/' . $channel['channel_id']),
+ dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']),
+ dbesc($xchan['xchan_hash'])
+ );
+ }
+ else {
+ $photos = import_xchan_photo($xchan['xchan_photo_l'],$xchan['xchan_hash']);
+ if($photos[4])
+ $photodate = NULL_DATE;
+ else
+ $photodate = $xchan['xchan_photo_date'];
+
+ $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s', xchan_photo_date = '%s' where xchan_hash = '%s'",
+ dbesc($photos[0]),
+ dbesc($photos[1]),
+ dbesc($photos[2]),
+ dbesc($photos[3]),
+ dbesc($photodate),
+ dbesc($xchan['xchan_hash'])
+ );
+ }
}
logger('import step 7');
diff --git a/Zotlabs/Module/Invite.php b/Zotlabs/Module/Invite.php
index bbd98150d..0bcd1c1fa 100644
--- a/Zotlabs/Module/Invite.php
+++ b/Zotlabs/Module/Invite.php
@@ -95,7 +95,7 @@ class Invite extends \Zotlabs\Web\Controller {
return;
}
- nav_set_selected(t('Invite'));
+ nav_set_selected('Invite');
$tpl = get_markup_template('invite.tpl');
$invonly = false;
diff --git a/Zotlabs/Module/Item.php b/Zotlabs/Module/Item.php
index eb8b60931..9e5dcfaff 100644
--- a/Zotlabs/Module/Item.php
+++ b/Zotlabs/Module/Item.php
@@ -659,14 +659,23 @@ class Item extends \Zotlabs\Web\Controller {
// BBCODE end alert
if(strlen($categories)) {
+
$cats = explode(',',$categories);
foreach($cats as $cat) {
+
+ if($webpage == ITEM_TYPE_CARD) {
+ $catlink = z_root() . '/cards/' . $channel['channel_address'] . '?f=&cat=' . urlencode(trim($cat));
+ }
+ else {
+ $catlink = $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat));
+ }
+
$post_tags[] = array(
'uid' => $profile_uid,
'ttype' => TERM_CATEGORY,
'otype' => TERM_OBJ_POST,
'term' => trim($cat),
- 'url' => $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat))
+ 'url' => $catlink
);
}
}
@@ -734,7 +743,9 @@ class Item extends \Zotlabs\Web\Controller {
if($parent_item)
$parent_mid = $parent_item['mid'];
-
+
+
+
// Fallback so that we alway have a thr_parent
if(!$thr_parent)
@@ -744,6 +755,21 @@ class Item extends \Zotlabs\Web\Controller {
$item_thread_top = ((! $parent) ? 1 : 0);
+
+ // fix permalinks for cards
+
+ if($webpage == ITEM_TYPE_CARD) {
+ $plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . (($pagetitle) ? $pagetitle : substr($mid,0,16));
+ }
+ if(($parent_item) && ($parent_item['item_type'] == ITEM_TYPE_CARD)) {
+ $r = q("select v from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.iid = %d limit 1",
+ intval($parent_item['id'])
+ );
+ if($r) {
+ $plink = z_root() . '/cards/' . $channel['channel_address'] . '/' . $r[0]['v'];
+ }
+ }
+
if ((! $plink) && ($item_thread_top)) {
$plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $mid;
}
@@ -1079,21 +1105,28 @@ class Item extends \Zotlabs\Web\Controller {
// if this is a different page type or it's just a local delete
// but not by the item author or owner, do a simple deletion
-
+
+ $complex = false;
+
if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) {
drop_item($i[0]['id']);
}
else {
// complex deletion that needs to propagate and be performed in phases
drop_item($i[0]['id'],true,DROPITEM_PHASE1);
- $r = q("select * from item where id = %d",
- intval($i[0]['id'])
- );
- if($r) {
- xchan_query($r);
- $sync_item = fetch_post_tags($r);
- build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true))));
- }
+ $complex = true;
+ }
+
+ $r = q("select * from item where id = %d",
+ intval($i[0]['id'])
+ );
+ if($r) {
+ xchan_query($r);
+ $sync_item = fetch_post_tags($r);
+ build_sync_packet($i[0]['uid'],array('item' => array(encode_item($sync_item[0],true))));
+ }
+
+ if($complex) {
tag_deliver($i[0]['uid'],$i[0]['id']);
}
}
diff --git a/Zotlabs/Module/Lang.php b/Zotlabs/Module/Lang.php
index 84776c3ea..0e5d85d05 100644
--- a/Zotlabs/Module/Lang.php
+++ b/Zotlabs/Module/Lang.php
@@ -5,7 +5,7 @@ namespace Zotlabs\Module;
class Lang extends \Zotlabs\Web\Controller {
function get() {
- nav_set_selected(t('Language'));
+ nav_set_selected('Language');
return lang_selector();
}
diff --git a/Zotlabs/Module/Like.php b/Zotlabs/Module/Like.php
index c995079ce..b104a5f5f 100644
--- a/Zotlabs/Module/Like.php
+++ b/Zotlabs/Module/Like.php
@@ -255,7 +255,7 @@ class Like extends \Zotlabs\Web\Controller {
// get the item. Allow linked photos (which are normally hidden) to be liked
$r = q("SELECT * FROM item WHERE id = %d
- and item_type = 0 and item_deleted = 0 and item_unpublished = 0
+ and (item_type = 0 or item_type = 6) and item_deleted = 0 and item_unpublished = 0
and item_delayed = 0 and item_pending_remove = 0 and item_blocked = 0 LIMIT 1",
intval($item_id)
);
diff --git a/Zotlabs/Module/Linkinfo.php b/Zotlabs/Module/Linkinfo.php
index 8f8231c49..78c34583e 100644
--- a/Zotlabs/Module/Linkinfo.php
+++ b/Zotlabs/Module/Linkinfo.php
@@ -95,7 +95,7 @@ class Linkinfo extends \Zotlabs\Web\Controller {
echo $arr['text'];
killme();
}
-
+
if($process_oembed) {
$x = oembed_process($url);
if($x) {
diff --git a/Zotlabs/Module/Logout.php b/Zotlabs/Module/Logout.php
new file mode 100644
index 000000000..6aa11d110
--- /dev/null
+++ b/Zotlabs/Module/Logout.php
@@ -0,0 +1,12 @@
+<?php
+
+namespace Zotlabs\Module;
+
+class Logout extends \Zotlabs\Web\Controller {
+
+ function init() {
+ \App::$session->nuke();
+ goaway(z_root());
+
+ }
+} \ No newline at end of file
diff --git a/Zotlabs/Module/Magic.php b/Zotlabs/Module/Magic.php
index 9ee5f9324..879085f96 100644
--- a/Zotlabs/Module/Magic.php
+++ b/Zotlabs/Module/Magic.php
@@ -17,6 +17,7 @@ class Magic extends \Zotlabs\Web\Controller {
$dest = ((x($_REQUEST,'dest')) ? $_REQUEST['dest'] : '');
$test = ((x($_REQUEST,'test')) ? intval($_REQUEST['test']) : 0);
$rev = ((x($_REQUEST,'rev')) ? intval($_REQUEST['rev']) : 0);
+ $owa = ((x($_REQUEST,'owa')) ? intval($_REQUEST['owa']) : 0);
$delegate = ((x($_REQUEST,'delegate')) ? $_REQUEST['delegate'] : '');
$parsed = parse_url($dest);
@@ -132,12 +133,32 @@ class Magic extends \Zotlabs\Web\Controller {
if(local_channel()) {
$channel = \App::get_channel();
+ // OpenWebAuth
+
+ if($owa) {
+
+ $headers = [];
+ $headers['Accept'] = 'application/x-zot+json' ;
+ $headers['X-Open-Web-Auth'] = random_string();
+ $headers = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],
+ 'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false,true,'sha512');
+ $x = z_fetch_url($basepath . '/owa',false,$redirects,[ 'headers' => $headers ]);
+
+ if($x['success']) {
+ $j = json_decode($x['body'],true);
+ if($j['success'] && $j['token']) {
+ $x = strpbrk($dest,'?&');
+ $args = (($x) ? '&owt=' . $j['token'] : '?f=&owt=' . $j['token']) . (($delegate) ? '&delegate=1' : '');
+
+ goaway($dest . $args);
+ }
+ }
+ goaway($dest);
+ }
+
+
$token = random_string();
- $token_sig = base64url_encode(rsa_sign($token,$channel['channel_prvkey']));
-
- $channel['token'] = $token;
- $channel['token_sig'] = $token_sig;
-
+
\Zotlabs\Zot\Verify::create('auth',$channel['channel_id'],$token,$x[0]['hubloc_url']);
$target_url = $x[0]['hubloc_callback'] . '/?f=&auth=' . urlencode(channel_reddress($channel))
diff --git a/Zotlabs/Module/Mail.php b/Zotlabs/Module/Mail.php
index e5509961a..12f3b8152 100644
--- a/Zotlabs/Module/Mail.php
+++ b/Zotlabs/Module/Mail.php
@@ -140,7 +140,7 @@ class Mail extends \Zotlabs\Web\Controller {
function get() {
$o = '';
- nav_set_selected(t('Mail'));
+ nav_set_selected('Mail');
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
diff --git a/Zotlabs/Module/Manage.php b/Zotlabs/Module/Manage.php
index 2d8f39ded..9c5c32294 100644
--- a/Zotlabs/Module/Manage.php
+++ b/Zotlabs/Module/Manage.php
@@ -11,7 +11,7 @@ class Manage extends \Zotlabs\Web\Controller {
return;
}
- nav_set_selected('Manage');
+ nav_set_selected('Channel Manager');
require_once('include/security.php');
diff --git a/Zotlabs/Module/Moderate.php b/Zotlabs/Module/Moderate.php
index 9af43420d..cf1625a6b 100644
--- a/Zotlabs/Module/Moderate.php
+++ b/Zotlabs/Module/Moderate.php
@@ -14,6 +14,24 @@ class Moderate extends \Zotlabs\Web\Controller {
return;
}
+ //show all items
+ if(argc() == 1) {
+ $r = q("select item.id as item_id, item.* from item where item.uid = %d and item_blocked = %d and item_deleted = 0 order by created desc limit 60",
+ intval(local_channel()),
+ intval(ITEM_MODERATED)
+ );
+ }
+
+ //show a single item
+ if(argc() == 2) {
+ $post_id = intval(argv(1));
+
+ $r = q("select item.id as item_id, item.* from item where item.id = %d and item.uid = %d and item_blocked = %d and item_deleted = 0 order by created desc limit 60",
+ intval($post_id),
+ intval(local_channel()),
+ intval(ITEM_MODERATED)
+ );
+ }
if(argc() > 2) {
$post_id = intval(argv(1));
@@ -55,10 +73,6 @@ class Moderate extends \Zotlabs\Web\Controller {
goaway(z_root() . '/moderate');
}
}
- $r = q("select item.id as item_id, item.* from item where item.uid = %d and item_blocked = %d and item_deleted = 0 order by created desc limit 60",
- intval(local_channel()),
- intval(ITEM_MODERATED)
- );
if($r) {
xchan_query($r);
@@ -73,4 +87,4 @@ class Moderate extends \Zotlabs\Web\Controller {
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Module/Mood.php b/Zotlabs/Module/Mood.php
index 85c8a3042..ad29ec7e8 100644
--- a/Zotlabs/Module/Mood.php
+++ b/Zotlabs/Module/Mood.php
@@ -117,7 +117,7 @@ class Mood extends \Zotlabs\Web\Controller {
return;
}
- nav_set_selected(t('Mood'));
+ nav_set_selected('Mood');
$parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : '0');
diff --git a/Zotlabs/Module/Network.php b/Zotlabs/Module/Network.php
index e5c059af5..ee736ff42 100644
--- a/Zotlabs/Module/Network.php
+++ b/Zotlabs/Module/Network.php
@@ -44,6 +44,7 @@ class Network extends \Zotlabs\Web\Controller {
$channel = \App::get_channel();
$item_normal = item_normal();
+ $item_normal_update = item_normal_update();
$datequery = $datequery2 = '';
@@ -116,7 +117,6 @@ class Network extends \Zotlabs\Web\Controller {
$spam = ((x($_GET,'spam')) ? intval($_GET['spam']) : 0);
$cmin = ((x($_GET,'cmin')) ? intval($_GET['cmin']) : 0);
$cmax = ((x($_GET,'cmax')) ? intval($_GET['cmax']) : 99);
- $firehose = ((x($_GET,'fh')) ? intval($_GET['fh']) : 0);
$file = ((x($_GET,'file')) ? $_GET['file'] : '');
$xchan = ((x($_GET,'xchan')) ? $_GET['xchan'] : '');
@@ -154,7 +154,7 @@ class Network extends \Zotlabs\Web\Controller {
));
}
- nav_set_selected(t('Activity'));
+ nav_set_selected('Grid');
$channel_acl = array(
'allow_cid' => $channel['channel_allow_cid'],
@@ -290,9 +290,6 @@ class Network extends \Zotlabs\Web\Controller {
// We only launch liveUpdate if you aren't filtering in some incompatible
// way and also you aren't writing a comment (discovered in javascript).
- if($gid || $cid || $cmin || ($cmax != 99) || $star || $liked || $conv || $spam || $nouveau || $list)
- $firehose = 0;
-
$maxheight = get_pconfig(local_channel(),'system','network_divmore_height');
if(! $maxheight)
$maxheight = 400;
@@ -315,7 +312,7 @@ class Network extends \Zotlabs\Web\Controller {
'$liked' => (($liked) ? $liked : '0'),
'$conv' => (($conv) ? $conv : '0'),
'$spam' => (($spam) ? $spam : '0'),
- '$fh' => (($firehose) ? $firehose : '0'),
+ '$fh' => '0',
'$nouveau' => (($nouveau) ? $nouveau : '0'),
'$wall' => '0',
'$static' => $static,
@@ -409,17 +406,7 @@ class Network extends \Zotlabs\Web\Controller {
}
$abook_uids = " and abook.abook_channel = " . local_channel() . " ";
-
- $disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false;
- if($firehose && (! $disable_discover_tab)) {
- require_once('include/channel.php');
- $sys = get_sys_channel();
- $uids = " and item.uid = " . intval($sys['channel_id']) . " ";
- \App::$data['firehose'] = intval($sys['channel_id']);
- }
- else {
- $uids = " and item.uid = " . local_channel() . " ";
- }
+ $uids = " and item.uid = " . local_channel() . " ";
if(get_pconfig(local_channel(),'system','network_list_mode'))
$page_mode = 'list';
@@ -491,10 +478,11 @@ class Network extends \Zotlabs\Web\Controller {
}
else {
+
// this is an update
$r = q("SELECT item.parent AS item_id FROM item
left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids )
- WHERE true $uids $item_normal $simple_update
+ WHERE true $uids $item_normal_update $simple_update
and (abook.abook_blocked = 0 or abook.abook_flags is null)
$sql_extra3 $sql_extra $sql_nets "
);
@@ -516,14 +504,14 @@ class Network extends \Zotlabs\Web\Controller {
dbesc($parents_str)
);
- xchan_query($items,true,(($firehose) ? local_channel() : 0));
+ xchan_query($items,true);
$items = fetch_post_tags($items,true);
$items = conv_sort($items,$ordering);
}
else {
$items = array();
}
-
+
if($page_mode === 'list') {
/**
@@ -535,20 +523,26 @@ class Network extends \Zotlabs\Web\Controller {
if($parents_str) {
$update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )";
+ $update_unseen .= " AND obj_type != '" . dbesc(ACTIVITY_OBJ_FILE) . "'";
$update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) ";
}
}
else {
if($parents_str) {
- $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )";
+ $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " ) AND obj_type != '" . dbesc(ACTIVITY_OBJ_FILE) . "'";
}
}
}
- if(($update_unseen) && (! $firehose))
- $r = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d $update_unseen ",
- intval(local_channel())
- );
+ if($update_unseen) {
+ $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ];
+ call_hooks('update_unseen',$x);
+ if($x['update'] === 'unset' || intval($x['update'])) {
+ $r = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d $update_unseen ",
+ intval(local_channel())
+ );
+ }
+ }
$mode = (($nouveau) ? 'network-new' : 'network');
diff --git a/Zotlabs/Module/New_channel.php b/Zotlabs/Module/New_channel.php
index cfd45e909..2b73fa191 100644
--- a/Zotlabs/Module/New_channel.php
+++ b/Zotlabs/Module/New_channel.php
@@ -9,7 +9,7 @@ require_once('include/permissions.php');
class New_channel extends \Zotlabs\Web\Controller {
function init() {
-
+
$cmd = ((argc() > 1) ? argv(1) : '');
if($cmd === 'autofill.json') {
diff --git a/Zotlabs/Module/Notifications.php b/Zotlabs/Module/Notifications.php
index 652648701..dfa007548 100644
--- a/Zotlabs/Module/Notifications.php
+++ b/Zotlabs/Module/Notifications.php
@@ -12,25 +12,44 @@ class Notifications extends \Zotlabs\Web\Controller {
return;
}
- nav_set_selected('notifications');
+ nav_set_selected('Notifications');
$o = '';
-
- $r = q("SELECT * from notify where uid = %d and seen = 0 order by created desc",
+
+ $r = q("select count(*) as total from notify where uid = %d and seen = 0",
intval(local_channel())
);
+ if($r && intval($t[0]['total']) > 49) {
+ $r = q("select * from notify where uid = %d
+ and seen = 0 order by created desc limit 50",
+ intval(local_channel())
+ );
+ } else {
+ $r1 = q("select * from notify where uid = %d
+ and seen = 0 order by created desc limit 50",
+ intval(local_channel())
+ );
+ $r2 = q("select * from notify where uid = %d
+ and seen = 1 order by created desc limit %d",
+ intval(local_channel()),
+ intval(50 - intval($t[0]['total']))
+ );
+ $r = array_merge($r1,$r2);
+ }
if($r) {
$notifications_available = 1;
- foreach ($r as $it) {
- $x = strip_tags(bbcode($it['msg']));
+ foreach ($r as $rr) {
+ $x = strip_tags(bbcode($rr['msg']));
if(strpos($x,','))
$x = substr($x,strpos($x,',')+1);
$notif_content .= replace_macros(get_markup_template('notify.tpl'),array(
- '$item_link' => z_root().'/notify/view/'. $it['id'],
- '$item_image' => $it['photo'],
+ '$item_link' => z_root().'/notify/view/'. $rr['id'],
+ '$item_image' => $rr['photo'],
'$item_text' => $x,
- '$item_when' => relative_date($it['created'])
+ '$item_when' => relative_date($rr['created']),
+ '$item_seen' => (($rr['seen']) ? true : false),
+ '$new' => t('New')
));
}
}
diff --git a/Zotlabs/Module/Notify.php b/Zotlabs/Module/Notify.php
index f592f6f37..3d6e1c2e7 100644
--- a/Zotlabs/Module/Notify.php
+++ b/Zotlabs/Module/Notify.php
@@ -15,12 +15,16 @@ class Notify extends \Zotlabs\Web\Controller {
intval(local_channel())
);
if($r) {
- q("update notify set seen = 1 where (( parent != '' and parent = '%s' and otype = '%s' ) or link = '%s' ) and uid = %d",
- dbesc($r[0]['parent']),
- dbesc($r[0]['otype']),
- dbesc($r[0]['link']),
- intval(local_channel())
- );
+ $x = [ 'channel_id' => local_channel(), 'update' => 'unset' ];
+ call_hooks('update_unseen',$x);
+ if($x['update'] === 'unset' || intval($x['update'])) {
+ q("update notify set seen = 1 where (( parent != '' and parent = '%s' and otype = '%s' ) or link = '%s' ) and uid = %d",
+ dbesc($r[0]['parent']),
+ dbesc($r[0]['otype']),
+ dbesc($r[0]['link']),
+ intval(local_channel())
+ );
+ }
goaway($r[0]['link']);
}
goaway(z_root());
diff --git a/Zotlabs/Module/Oep.php b/Zotlabs/Module/Oep.php
index 9c05f5e3f..5e06d3540 100644
--- a/Zotlabs/Module/Oep.php
+++ b/Zotlabs/Module/Oep.php
@@ -1,6 +1,8 @@
<?php
namespace Zotlabs\Module;
+require_once('include/security.php');
+
// oembed provider
@@ -41,6 +43,8 @@ class Oep extends \Zotlabs\Web\Controller {
$arr = $this->oep_profile_reply($_REQUEST);
elseif(fnmatch('*/profile/*',$url))
$arr = $this->oep_profile_reply($_REQUEST);
+ elseif(fnmatch('*/cards/*',$url))
+ $arr = $this->oep_cards_reply($_REQUEST);
if($arr) {
if($html) {
@@ -66,45 +70,70 @@ class Oep extends \Zotlabs\Web\Controller {
$url = $args['url'];
$maxwidth = intval($args['maxwidth']);
$maxheight = intval($args['maxheight']);
-
- if(preg_match('#//(.*?)/(.*?)/(.*?)/(.*?)mid\=(.*?)(&|$)#',$url,$matches)) {
- $chn = $matches[3];
- $res = $matches[5];
+ logger('processing display');
+ if(preg_match('#//(.*?)/display/(.*?)(&|\?|$)#',$url,$matches)) {
+ $res = $matches[2];
}
-
- if(! ($chn && $res))
- return;
- $c = q("select * from channel where channel_address = '%s' limit 1",
- dbesc($chn)
+
+ if(strpos($res,'b64.') === 0) {
+ $res = base64url_decode(substr($res,4));
+ }
+
+ $item_normal = item_normal();
+
+ $p = q("select * from item where mid like '%s' limit 1",
+ dbesc($res . '%')
);
-
- if(! $c)
+
+ if(! $p)
return;
+
+ $c = channelx_by_n($p[0]['uid']);
+
- $sql_extra = item_permissions_sql($c[0]['channel_id']);
+ if(! ($c && $res))
+ return;
+
+ if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_stream'))
+ return;
+
+ $sql_extra = item_permissions_sql($c['channel_id']);
- $p = q("select * from item where mid = '%s' and uid = %d $sql_extra limit 1",
- dbesc($res),
- intval($c[0]['channel_id'])
+ $p = q("select * from item where mid like '%s' and uid = %d $sql_extra $item_normal limit 1",
+ dbesc($res . '%'),
+ intval($c['channel_id'])
);
+
if(! $p)
return;
xchan_query($p,true);
$p = fetch_post_tags($p,true);
+
+ // This function can get tripped up if the item is already a reshare
+ // (the multiple share declarations do not parse cleanly if nested)
+ // So build a template with a known nonsense string as the content, and then
+ // replace that known string with the actual rendered content, sending
+ // each content layer through bbcode() separately.
+
+ $x = '2eGriplW^*Jmf4';
+
$o = "[share author='".urlencode($p[0]['author']['xchan_name']).
- "' profile='".$p[0]['author']['xchan_url'] .
- "' avatar='".$p[0]['author']['xchan_photo_s'].
- "' link='".$p[0]['plink'].
- "' posted='".$p[0]['created'].
- "' message_id='".$p[0]['mid']."']";
+ "' profile='".$p[0]['author']['xchan_url'] .
+ "' avatar='".$p[0]['author']['xchan_photo_s'].
+ "' link='".$p[0]['plink'].
+ "' posted='".$p[0]['created'].
+ "' message_id='".$p[0]['mid']."']";
if($p[0]['title'])
- $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
- $o .= $p[0]['body'];
- $o .= "[/share]";
+ $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
+
+ $o .= $x;
+ $o .= "[/share]";
$o = bbcode($o);
+ $o = str_replace($x,bbcode($p[0]['body']),$o);
+
$ret['type'] = 'rich';
$w = (($maxwidth) ? $maxwidth : 640);
@@ -118,6 +147,91 @@ class Oep extends \Zotlabs\Web\Controller {
return $ret;
}
+
+
+ function oep_cards_reply($args) {
+
+ $ret = [];
+ $url = $args['url'];
+ $maxwidth = intval($args['maxwidth']);
+ $maxheight = intval($args['maxheight']);
+
+ if(preg_match('#//(.*?)/cards/(.*?)/(.*?)(&|\?|$)#',$url,$matches)) {
+ $nick = $matches[2];
+ $res = $matches[3];
+ }
+ if(! ($nick && $res))
+ return $ret;
+
+ $channel = channelx_by_nick($nick);
+
+ if(! $channel)
+ return $ret;
+
+
+ if(! perm_is_allowed($channel['channel_id'],get_observer_hash(),'view_pages'))
+ return $ret;
+
+ $sql_extra = item_permissions_sql($channel['channel_id'],get_observer_hash());
+
+ $r = q("select * from iconfig where iconfig.cat = 'system' and iconfig.k = 'CARD' and iconfig.v = '%s' limit 1",
+ dbesc($res)
+ );
+ if($r) {
+ $sql_extra = "and item.id = " . intval($r[0]['iid']) . " ";
+ }
+ else {
+ return $ret;
+ }
+
+ $r = q("select * from item
+ where item.uid = %d and item_type = %d
+ $sql_extra order by item.created desc",
+ intval($channel['channel_id']),
+ intval(ITEM_TYPE_CARD)
+ );
+
+ $item_normal = " and item.item_hidden = 0 and item.item_type in (0,6) and item.item_deleted = 0
+ and item.item_unpublished = 0 and item.item_delayed = 0 and item.item_pending_remove = 0
+ and item.item_blocked = 0 ";
+
+ if($r) {
+ xchan_query($r);
+ $p = fetch_post_tags($r, true);
+ }
+
+ $x = '2eGriplW^*Jmf4';
+
+
+ $o = "[share author='".urlencode($p[0]['author']['xchan_name']).
+ "' profile='".$p[0]['author']['xchan_url'] .
+ "' avatar='".$p[0]['author']['xchan_photo_s'].
+ "' link='".$p[0]['plink'].
+ "' posted='".$p[0]['created'].
+ "' message_id='".$p[0]['mid']."']";
+ if($p[0]['title'])
+ $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
+
+ $o .= $x;
+ $o .= "[/share]";
+ $o = bbcode($o);
+
+ $o = str_replace($x,bbcode($p[0]['body']),$o);
+
+ $ret['type'] = 'rich';
+
+ $w = (($maxwidth) ? $maxwidth : 640);
+ $h = (($maxheight) ? $maxheight : intval($w * 2 / 3));
+
+ $ret['html'] = '<div style="width: ' . $w . '; height: ' . $h . '; font-family: sans-serif,arial,freesans;" >' . $o . '</div>';
+
+ $ret['width'] = $w;
+ $ret['height'] = $h;
+
+ return $ret;
+
+ }
+
function oep_mid_reply($args) {
@@ -139,6 +253,9 @@ class Oep extends \Zotlabs\Web\Controller {
if(! $c)
return;
+
+ if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_stream'))
+ return;
$sql_extra = item_permissions_sql($c[0]['channel_id']);
@@ -151,19 +268,29 @@ class Oep extends \Zotlabs\Web\Controller {
xchan_query($p,true);
$p = fetch_post_tags($p,true);
-
+
+ // This function can get tripped up if the item is already a reshare
+ // (the multiple share declarations do not parse cleanly if nested)
+ // So build a template with a known nonsense string as the content, and then
+ // replace that known string with the actual rendered content, sending
+ // each content layer through bbcode() separately.
+
+ $x = '2eGriplW^*Jmf4';
+
$o = "[share author='".urlencode($p[0]['author']['xchan_name']).
- "' profile='".$p[0]['author']['xchan_url'] .
- "' avatar='".$p[0]['author']['xchan_photo_s'].
- "' link='".$p[0]['plink'].
- "' posted='".$p[0]['created'].
- "' message_id='".$p[0]['mid']."']";
- if($p[0]['title'])
- $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
- $o .= $p[0]['body'];
- $o .= "[/share]";
+ "' profile='".$p[0]['author']['xchan_url'] .
+ "' avatar='".$p[0]['author']['xchan_photo_s'].
+ "' link='".$p[0]['plink'].
+ "' posted='".$p[0]['created'].
+ "' message_id='".$p[0]['mid']."']";
+ if($p[0]['title'])
+ $o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
+ $o .= $x;
+ $o .= "[/share]";
$o = bbcode($o);
+ $o = str_replace($x,bbcode($p[0]['body']),$o);
+
$ret['type'] = 'rich';
$w = (($maxwidth) ? $maxwidth : 640);
@@ -247,6 +374,9 @@ class Oep extends \Zotlabs\Web\Controller {
if(! $c)
return;
+ if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_files'))
+ return;
+
$sql_extra = permissions_sql($c[0]['channel_id']);
$p = q("select resource_id from photo where album = '%s' and uid = %d and imgscale = 0 $sql_extra order by created desc limit 1",
@@ -308,6 +438,9 @@ class Oep extends \Zotlabs\Web\Controller {
if(! $c)
return;
+ if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_files'))
+ return;
+
$sql_extra = permissions_sql($c[0]['channel_id']);
$p = q("select resource_id from photo where uid = %d and imgscale = 0 $sql_extra order by created desc limit 1",
@@ -368,7 +501,10 @@ class Oep extends \Zotlabs\Web\Controller {
if(! $c)
return;
-
+
+ if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_files'))
+ return;
+
$sql_extra = permissions_sql($c[0]['channel_id']);
diff --git a/Zotlabs/Module/Ofeed.php b/Zotlabs/Module/Ofeed.php
index 2b7acff99..58488d4af 100644
--- a/Zotlabs/Module/Ofeed.php
+++ b/Zotlabs/Module/Ofeed.php
@@ -18,7 +18,7 @@ class Ofeed extends \Zotlabs\Web\Controller {
$params['pages'] = ((x($_REQUEST,'pages')) ? intval($_REQUEST['pages']) : 0);
$params['top'] = ((x($_REQUEST,'top')) ? intval($_REQUEST['top']) : 0);
$params['start'] = ((x($params,'start')) ? intval($params['start']) : 0);
- $params['records'] = ((x($params,'records')) ? intval($params['records']) : 40);
+ $params['records'] = ((x($params,'records')) ? intval($params['records']) : 10);
$params['direction'] = ((x($params,'direction')) ? dbesc($params['direction']) : 'desc');
$params['cat'] = ((x($_REQUEST,'cat')) ? escape_tags($_REQUEST['cat']) : '');
$params['compat'] = ((x($_REQUEST,'compat')) ? intval($_REQUEST['compat']) : 1);
diff --git a/Zotlabs/Module/Owa.php b/Zotlabs/Module/Owa.php
new file mode 100644
index 000000000..4b0d855c5
--- /dev/null
+++ b/Zotlabs/Module/Owa.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Zotlabs\Module;
+
+/**
+ * OpenWebAuth verifier and token generator
+ * See https://macgirvin.com/wiki/mike/OpenWebAuth/Home
+ * Requests to this endpoint should be signed using HTTP Signatures
+ * using the 'Authorization: Signature' authentication method
+ * If the signature verifies a token is returned.
+ *
+ * This token may be exchanged for an authenticated cookie.
+ */
+
+class Owa extends \Zotlabs\Web\Controller {
+
+ function init() {
+
+ $ret = [ 'success' => false ];
+
+ foreach([ 'REDIRECT_REMOTE_USER', 'HTTP_AUTHORIZATION' ] as $head) {
+ if(array_key_exists($head,$_SERVER) && substr(trim($_SERVER[$head]),0,9) === 'Signature') {
+ if($head !== 'HTTP_AUTHORIZATION') {
+ $_SERVER['HTTP_AUTHORIZATION'] = $_SERVER[$head];
+ continue;
+ }
+
+ $sigblock = \Zotlabs\Web\HTTPSig::parse_sigheader($_SERVER[$head]);
+ if($sigblock) {
+ $keyId = $sigblock['keyId'];
+
+ if($keyId) {
+ $r = q("select * from hubloc left join xchan on hubloc_hash = xchan_hash
+ where hubloc_addr = '%s' limit 1",
+ dbesc(str_replace('acct:','',$keyId))
+ );
+ if($r) {
+ $hubloc = $r[0];
+ $verified = \Zotlabs\Web\HTTPSig::verify('',$hubloc['xchan_pubkey']);
+ if($verified && $verified['header_signed'] && $verified['header_valid']) {
+ $ret['success'] = true;
+ $token = random_string(32);
+ \Zotlabs\Zot\Verify::create('owt',0,$token,$r[0]['hubloc_addr']);
+ $ret['token'] = $token;
+ }
+ }
+ }
+ }
+ }
+ }
+ json_return_and_die($ret,'application/x-zot+json');
+ }
+}
diff --git a/Zotlabs/Module/Pdledit.php b/Zotlabs/Module/Pdledit.php
index 618444480..f8af470ac 100644
--- a/Zotlabs/Module/Pdledit.php
+++ b/Zotlabs/Module/Pdledit.php
@@ -14,7 +14,7 @@ class Pdledit extends \Zotlabs\Web\Controller {
if(! trim($_REQUEST['content'])) {
del_pconfig(local_channel(),'system','mod_' . $_REQUEST['module'] . '.pdl');
- goaway(z_root() . '/pdledit/' . $_REQUEST['module']);
+ goaway(z_root() . '/pdledit');
}
set_pconfig(local_channel(),'system','mod_' . $_REQUEST['module'] . '.pdl',escape_tags($_REQUEST['content']));
build_sync_packet();
@@ -34,19 +34,38 @@ class Pdledit extends \Zotlabs\Web\Controller {
notice( t('Feature disabled.') . EOL);
return;
}
-
+
+ if(argc() > 2 && argv(2) === 'reset') {
+ del_pconfig(local_channel(),'system','mod_' . argv(1) . '.pdl');
+ goaway(z_root() . '/pdledit');
+ }
+
if(argc() > 1)
$module = 'mod_' . argv(1) . '.pdl';
else {
$o .= '<div class="generic-content-wrapper-styled">';
$o .= '<h1>' . t('Edit System Page Description') . '</h1>';
+
+ $edited = [];
+
+ $r = q("select k from pconfig where uid = %d and cat = 'system' and k like '%s' ",
+ intval(local_channel()),
+ dbesc('mod_%.pdl')
+ );
+
+ if($r) {
+ foreach($r as $rv) {
+ $edited[] = substr(str_replace('.pdl','',$rv['k']),4);
+ }
+ }
+
$files = glob('Zotlabs/Module/*.php');
if($files) {
foreach($files as $f) {
$name = lcfirst(basename($f,'.php'));
$x = theme_include('mod_' . $name . '.pdl');
if($x) {
- $o .= '<a href="pdledit/' . $name . '" >' . $name . '</a><br />';
+ $o .= '<a href="pdledit/' . $name . '" >' . $name . '</a>' . ((in_array($name,$edited)) ? ' ' . t('(modified)') . ' <a href="pdledit/' . $name . '/reset" >' . t('Reset') . '</a>': '' ) . '<br />';
}
}
}
@@ -69,6 +88,7 @@ class Pdledit extends \Zotlabs\Web\Controller {
'$header' => t('Edit System Page Description'),
'$mname' => t('Module Name:'),
'$help' => t('Layout Help'),
+ '$another' => t('Edit another layout'),
'$module' => argv(1),
'$content' => htmlspecialchars($t,ENT_COMPAT,'UTF-8'),
'$submit' => t('Submit')
diff --git a/Zotlabs/Module/Photos.php b/Zotlabs/Module/Photos.php
index 85dae46a5..caef45d98 100644
--- a/Zotlabs/Module/Photos.php
+++ b/Zotlabs/Module/Photos.php
@@ -555,7 +555,7 @@ class Photos extends \Zotlabs\Web\Controller {
$sql_extra = permissions_sql($owner_uid,get_observer_hash(),'photo');
$sql_attach = permissions_sql($owner_uid,get_observer_hash(),'attach');
- nav_set_selected(t('Photos'));
+ nav_set_selected('Photos');
$o = "";
@@ -671,8 +671,13 @@ class Photos extends \Zotlabs\Web\Controller {
*/
if($datatype === 'album') {
-
- \App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$cmd) . '" title="oembed" />' . "\r\n";
+
+ head_add_link([
+ 'rel' => 'alternate',
+ 'type' => 'application/json+oembed',
+ 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string),
+ 'title' => 'oembed'
+ ]);
if($x = photos_album_exists($owner_uid, get_observer_hash(), $datum)) {
\App::set_pager_itemspage(60);
@@ -765,7 +770,7 @@ class Photos extends \Zotlabs\Web\Controller {
if($photos) {
$o = replace_macros(get_markup_template('photosajax.tpl'),array(
'$photos' => $photos,
- '$album_id' => bin2hex($album)
+ '$album_id' => $datum
));
}
else {
diff --git a/Zotlabs/Module/Ping.php b/Zotlabs/Module/Ping.php
index bf2fa5cc9..c91659f2f 100644
--- a/Zotlabs/Module/Ping.php
+++ b/Zotlabs/Module/Ping.php
@@ -19,6 +19,7 @@ class Ping extends \Zotlabs\Web\Controller {
* @result JSON
*/
function init() {
+
$result = array();
$notifs = array();
@@ -36,6 +37,11 @@ class Ping extends \Zotlabs\Web\Controller {
$result['all_events_today'] = 0;
$result['notice'] = array();
$result['info'] = array();
+ $result['pubs'] = 0;
+ $result['files'] = 0;
+
+ if(! $_SESSION['static_loadtime'])
+ $_SESSION['static_loadtime'] = datetime_convert();
$t0 = dba_timer();
@@ -134,6 +140,61 @@ class Ping extends \Zotlabs\Web\Controller {
db_utcnow(), db_quoteinterval('3 MINUTE')
);
+ $discover_tab_on = ((get_config('system','disable_discover_tab') != 1) ? true : false);
+ $notify_pubs = ((local_channel()) ? ($vnotify & VNOTIFY_PUBS) && $discover_tab_on : $discover_tab_on);
+
+ if($notify_pubs) {
+ $sys = get_sys_channel();
+
+ $pubs = q("SELECT count(id) as total from item
+ WHERE uid = %d
+ AND author_xchan != '%s'
+ AND obj_type != '%s'
+ AND item_unseen = 1
+ AND created > '" . datetime_convert('UTC','UTC',$_SESSION['static_loadtime']) . "'
+ $item_normal",
+ intval($sys['channel_id']),
+ dbesc(get_observer_hash()),
+ dbesc(ACTIVITY_OBJ_FILE)
+ );
+
+ if($pubs)
+ $result['pubs'] = intval($pubs[0]['total']);
+ }
+
+ if((argc() > 1) && (argv(1) === 'pubs') && ($notify_pubs)) {
+ $sys = get_sys_channel();
+ $result = array();
+
+ $r = q("SELECT * FROM item
+ WHERE uid = %d
+ AND author_xchan != '%s'
+ AND obj_type != '%s'
+ AND item_unseen = 1
+ AND created > '" . datetime_convert('UTC','UTC',$_SESSION['static_loadtime']) . "'
+ $item_normal
+ ORDER BY created DESC
+ LIMIT 300",
+ intval($sys['channel_id']),
+ dbesc(get_observer_hash()),
+ dbesc(ACTIVITY_OBJ_FILE)
+ );
+
+ if($r) {
+ xchan_query($r);
+ foreach($r as $rr) {
+ $rr['llink'] = str_replace('display/', 'pubstream/?f=&mid=', $rr['llink']);
+ $result[] = \Zotlabs\Lib\Enotify::format($rr);
+ }
+ }
+
+// logger('ping (network||home): ' . print_r($result, true), LOGGER_DATA);
+ echo json_encode(array('notify' => $result));
+ killme();
+ }
+
+ $t1 = dba_timer();
+
if((! local_channel()) || ($result['invalid'])) {
echo json_encode($result);
killme();
@@ -177,6 +238,9 @@ class Ping extends \Zotlabs\Web\Controller {
intval(local_channel())
);
break;
+ case 'pubs':
+ unset($_SESSION['static_loadtime']);
+ break;
default:
break;
}
@@ -194,37 +258,20 @@ class Ping extends \Zotlabs\Web\Controller {
* dropdown menu.
*/
if(argc() > 1 && argv(1) === 'notify') {
- $t = q("select count(*) as total from notify where uid = %d and seen = 0",
+ $t = q("select * from notify where uid = %d and seen = 0 order by created desc",
intval(local_channel())
);
- if($t && intval($t[0]['total']) > 49) {
- $z = q("select * from notify where uid = %d
- and seen = 0 order by created desc limit 50",
- intval(local_channel())
- );
- } else {
- $z1 = q("select * from notify where uid = %d
- and seen = 0 order by created desc limit 50",
- intval(local_channel())
- );
- $z2 = q("select * from notify where uid = %d
- and seen = 1 order by created desc limit %d",
- intval(local_channel()),
- intval(50 - intval($t[0]['total']))
- );
- $z = array_merge($z1,$z2);
- }
- if(count($z)) {
- foreach($z as $zz) {
+ if($t) {
+ foreach($t as $tt) {
$notifs[] = array(
- 'notify_link' => z_root() . '/notify/view/' . $zz['id'],
- 'name' => $zz['xname'],
- 'url' => $zz['url'],
- 'photo' => $zz['photo'],
- 'when' => relative_date($zz['created']),
- 'hclass' => (($zz['seen']) ? 'notify-seen' : 'notify-unseen'),
- 'message' => strip_tags(bbcode($zz['msg']))
+ 'notify_link' => z_root() . '/notify/view/' . $tt['id'],
+ 'name' => $tt['xname'],
+ 'url' => $tt['url'],
+ 'photo' => $tt['photo'],
+ 'when' => relative_date($tt['created']),
+ 'hclass' => (($tt['seen']) ? 'notify-seen' : 'notify-unseen'),
+ 'message' => strip_tags(bbcode($tt['msg']))
);
}
}
@@ -233,7 +280,7 @@ class Ping extends \Zotlabs\Web\Controller {
killme();
}
- if(argc() > 1 && argv(1) === 'messages') {
+ if(argc() > 1 && argv(1) === 'mail') {
$channel = \App::get_channel();
$t = q("select mail.*, xchan.* from mail left join xchan on xchan_hash = from_xchan
where channel_id = %d and mail_seen = 0 and mail_deleted = 0
@@ -265,9 +312,12 @@ class Ping extends \Zotlabs\Web\Controller {
$r = q("SELECT * FROM item
WHERE item_unseen = 1 and uid = %d $item_normal
- and author_xchan != '%s' ORDER BY created DESC limit 300",
+ AND author_xchan != '%s'
+ AND obj_type != '%s'
+ ORDER BY created DESC limit 300",
intval(local_channel()),
- dbesc($ob_hash)
+ dbesc($ob_hash),
+ dbesc(ACTIVITY_OBJ_FILE)
);
if($r) {
@@ -308,6 +358,30 @@ class Ping extends \Zotlabs\Web\Controller {
killme();
}
+ if((argc() > 1 && (argv(1) === 'register')) && is_site_admin()) {
+ $result = array();
+
+ $r = q("SELECT account_email, account_created from account where (account_flags & %d) > 0",
+ intval(ACCOUNT_PENDING)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $result[] = array(
+ 'notify_link' => z_root() . '/admin/accounts',
+ 'name' => $rr['account_email'],
+ 'url' => '',
+ 'photo' => get_default_profile_photo(48),
+ 'when' => relative_date($rr['account_created']),
+ 'hclass' => ('notify-unseen'),
+ 'message' => t('requires approval')
+ );
+ }
+ }
+ logger('ping (register): ' . print_r($result, true), LOGGER_DATA);
+ echo json_encode(array('notify' => $result));
+ killme();
+ }
+
if(argc() > 1 && (argv(1) === 'all_events')) {
$bd_format = t('g A l F d') ; // 8 AM Friday January 18
@@ -345,6 +419,39 @@ class Ping extends \Zotlabs\Web\Controller {
killme();
}
+ if(argc() > 1 && (argv(1) === 'files')) {
+ $result = array();
+
+ $r = q("SELECT item.created, xchan.xchan_name, xchan.xchan_url, xchan.xchan_photo_s FROM item
+ LEFT JOIN xchan on author_xchan = xchan_hash
+ WHERE item.verb = '%s'
+ AND item.obj_type = '%s'
+ AND item.uid = %d
+ AND item.owner_xchan != '%s'
+ AND item.item_unseen = 1",
+ dbesc(ACTIVITY_POST),
+ dbesc(ACTIVITY_OBJ_FILE),
+ intval(local_channel()),
+ dbesc($ob_hash)
+ );
+ if($r) {
+ foreach($r as $rr) {
+ $result[] = array(
+ 'notify_link' => z_root() . '/sharedwithme',
+ 'name' => $rr['xchan_name'],
+ 'url' => $rr['xchan_url'],
+ 'photo' => $rr['xchan_photo_s'],
+ 'when' => relative_date($rr['created']),
+ 'hclass' => ('notify-unseen'),
+ 'message' => t('shared a file with you')
+ );
+ }
+ }
+ logger('ping (files): ' . print_r($result, true), LOGGER_DATA);
+ echo json_encode(array('notify' => $result));
+ killme();
+ }
+
/**
* Normal ping - just the counts, no detail
*/
@@ -356,15 +463,35 @@ class Ping extends \Zotlabs\Web\Controller {
$result['notify'] = intval($t[0]['total']);
}
- $t1 = dba_timer();
+ $t2 = dba_timer();
+
+ if($vnotify & VNOTIFY_FILES) {
+ $files = q("SELECT count(id) as total FROM item
+ WHERE verb = '%s'
+ AND obj_type = '%s'
+ AND uid = %d
+ AND owner_xchan != '%s'
+ AND item_unseen = 1",
+ dbesc(ACTIVITY_POST),
+ dbesc(ACTIVITY_OBJ_FILE),
+ intval(local_channel()),
+ dbesc($ob_hash)
+ );
+ if($files)
+ $result['files'] = intval($files[0]['total']);
+ }
+
+ $t3 = dba_timer();
if($vnotify & (VNOTIFY_NETWORK|VNOTIFY_CHANNEL)) {
$r = q("SELECT id, item_wall FROM item
WHERE item_unseen = 1 and uid = %d
$item_normal
- and author_xchan != '%s'",
+ AND author_xchan != '%s'
+ AND obj_type != '%s'",
intval(local_channel()),
- dbesc($ob_hash)
+ dbesc($ob_hash),
+ dbesc(ACTIVITY_OBJ_FILE)
);
if($r) {
@@ -384,20 +511,20 @@ class Ping extends \Zotlabs\Web\Controller {
if(! ($vnotify & VNOTIFY_CHANNEL))
$result['home'] = 0;
- $t2 = dba_timer();
+ $t4 = dba_timer();
if($vnotify & VNOTIFY_INTRO) {
$intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ",
intval(local_channel())
);
- $t3 = dba_timer();
+ $t5 = dba_timer();
if($intr)
$result['intros'] = intval($intr[0]['total']);
}
- $t4 = dba_timer();
+ $t6 = dba_timer();
$channel = \App::get_channel();
if($vnotify & VNOTIFY_MAIL) {
@@ -420,7 +547,7 @@ class Ping extends \Zotlabs\Web\Controller {
}
}
- $t5 = dba_timer();
+ $t7 = dba_timer();
if($vnotify & (VNOTIFY_EVENT|VNOTIFY_EVENTTODAY|VNOTIFY_BIRTHDAY)) {
$events = q("SELECT etype, dtstart, adjust FROM event
@@ -466,9 +593,9 @@ class Ping extends \Zotlabs\Web\Controller {
$x = json_encode($result);
- $t6 = dba_timer();
+ $t8 = dba_timer();
-// logger('ping timer: ' . sprintf('%01.4f %01.4f %01.4f %01.4f %01.4f %01.4f',$t6 - $t5, $t5 - $t4, $t4 - $t3, $t3 - $t2, $t2 - $t1, $t1 - $t0));
+// logger('ping timer: ' . sprintf('%01.4f %01.4f %01.4f %01.4f %01.4f %01.4f %01.4f %01.4f',$t8 - $t7, $t7 - $t6, $t6 - $t5, $t5 - $t4, $t4 - $t3, $t3 - $t2, $t2 - $t1, $t1 - $t0));
echo $x;
killme();
diff --git a/Zotlabs/Module/Poke.php b/Zotlabs/Module/Poke.php
index 0bd1187c7..d13ec5ced 100644
--- a/Zotlabs/Module/Poke.php
+++ b/Zotlabs/Module/Poke.php
@@ -150,7 +150,7 @@ class Poke extends \Zotlabs\Web\Controller {
return;
}
- nav_set_selected(t('Poke'));
+ nav_set_selected('Poke');
$name = '';
$id = '';
diff --git a/Zotlabs/Module/Post.php b/Zotlabs/Module/Post.php
index c78484a45..f67cbf020 100644
--- a/Zotlabs/Module/Post.php
+++ b/Zotlabs/Module/Post.php
@@ -19,16 +19,16 @@ class Post extends \Zotlabs\Web\Controller {
function init() {
if(array_key_exists('auth', $_REQUEST)) {
$x = new \Zotlabs\Zot\Auth($_REQUEST);
-
exit;
}
}
function post() {
- $z = new \Zotlabs\Zot\Receiver($_REQUEST['data'], get_config('system', 'prvkey'), new \Zotlabs\Zot\ZotHandler());
+ if(array_key_exists('data',$_REQUEST)) {
+ $z = new \Zotlabs\Zot\Receiver($_REQUEST['data'], get_config('system', 'prvkey'), new \Zotlabs\Zot\ZotHandler());
+ exit;
+ }
- // notreached;
- exit;
}
}
diff --git a/Zotlabs/Module/Probe.php b/Zotlabs/Module/Probe.php
index 859bed315..2e65f107c 100644
--- a/Zotlabs/Module/Probe.php
+++ b/Zotlabs/Module/Probe.php
@@ -8,7 +8,7 @@ class Probe extends \Zotlabs\Web\Controller {
function get() {
- nav_set_selected(t('Remote Diagnostics'));
+ nav_set_selected('Remote Diagnostics');
$o .= '<h3>Probe Diagnostic</h3>';
diff --git a/Zotlabs/Module/Profile.php b/Zotlabs/Module/Profile.php
index 6930d50ca..43106e3af 100644
--- a/Zotlabs/Module/Profile.php
+++ b/Zotlabs/Module/Profile.php
@@ -94,7 +94,6 @@ class Profile extends \Zotlabs\Web\Controller {
echo \App::$profile['profile_vcard'];
killme();
}
-
$is_owner = ((local_channel()) && (local_channel() == \App::$profile['profile_uid']) ? true : false);
@@ -102,11 +101,14 @@ class Profile extends \Zotlabs\Web\Controller {
notice( t('Permission denied.') . EOL);
return;
}
-
- //$o .= profile_tabs($a, $is_owner, \App::$profile['channel_address']);
-
- \App::$page['htmlhead'] .= "\r\n" . '<link rel="alternate" type="application/json+oembed" href="' . z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string) . '" title="oembed" />' . "\r\n";
-
+
+ head_add_link([
+ 'rel' => 'alternate',
+ 'type' => 'application/json+oembed',
+ 'href' => z_root() . '/oep?f=&url=' . urlencode(z_root() . '/' . \App::$query_string),
+ 'title' => 'oembed'
+ ]);
+
$o .= advanced_profile($a);
call_hooks('profile_advanced',$o);
return $o;
diff --git a/Zotlabs/Module/Profile_photo.php b/Zotlabs/Module/Profile_photo.php
index 47b627015..27e6bc445 100644
--- a/Zotlabs/Module/Profile_photo.php
+++ b/Zotlabs/Module/Profile_photo.php
@@ -158,6 +158,9 @@ class Profile_photo extends \Zotlabs\Web\Controller {
intval(local_channel())
);
+
+
+
send_profile_photo_activity($channel,$base_image,$profile);
}
@@ -174,12 +177,17 @@ class Profile_photo extends \Zotlabs\Web\Controller {
// We'll set the updated profile-photo timestamp even if it isn't the default profile,
// so that browsers will do a cache update unconditionally
+ // Also set links back to site-specific profile photo url in case it was
+ // changed to a generic URL by a clone operation. Otherwise the new photo may
+ // not get pushed to other sites correctly.
-
- $r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s'
+ $r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s'
where xchan_hash = '%s'",
dbesc($im->getType()),
dbesc(datetime_convert()),
+ dbesc(z_root() . '/photo/profile/l/' . $channel['channel_id']),
+ dbesc(z_root() . '/photo/profile/m/' . $channel['channel_id']),
+ dbesc(z_root() . '/photo/profile/s/' . $channel['channel_id']),
dbesc($channel['xchan_hash'])
);
diff --git a/Zotlabs/Module/Pubsites.php b/Zotlabs/Module/Pubsites.php
index d87967189..daec5dde3 100644
--- a/Zotlabs/Module/Pubsites.php
+++ b/Zotlabs/Module/Pubsites.php
@@ -30,13 +30,14 @@ class Pubsites extends \Zotlabs\Web\Controller {
if($ret['success']) {
$j = json_decode($ret['body'],true);
if($j) {
- $o .= '<table class="table table-striped table-hover"><tr><td>' . t('Hub URL') . '</td><td>' . t('Access Type') . '</td><td>' . t('Registration Policy') . '</td><td>' . t('Stats') . '</td><td>' . t('Software') . '</td>';
+ $o .= '<table class="table table-striped table-hover"><tr><td>' . t('Hub URL') . '</td><td>' . t('Access Type') . '</td><td>' . t('Registration Policy') . '</td><!--td>' . t('Stats') . '</td--><td>' . t('Software') . '</td>';
if($rating_enabled)
$o .= '<td colspan="2">' . t('Ratings') . '</td>';
$o .= '</tr>';
if($j['sites']) {
foreach($j['sites'] as $jj) {
- if(! \Zotlabs\Lib\System::compatible_project($jj['project']))
+ $projectname = explode(' ',$jj['project']);
+ if(! \Zotlabs\Lib\System::compatible_project($projectname[0]))
continue;
if(strpos($jj['version'],' ')) {
$x = explode(' ', $jj['version']);
@@ -54,7 +55,7 @@ class Pubsites extends \Zotlabs\Web\Controller {
$location = '<br />&nbsp;';
}
$urltext = str_replace(array('https://'), '', $jj['url']);
- $o .= '<tr><td><a href="'. (($jj['sellpage']) ? $jj['sellpage'] : $jj['url'] . '/register' ) . '" ><i class="fa fa-link"></i> ' . $urltext . '</a>' . $location . '</td><td>' . $jj['access'] . '</td><td>' . $jj['register'] . '</td><td>' . '<a target="stats" href="https://hubchart-tarine.rhcloud.com/hub.jsp?hubFqdn=' . $m['host'] . '"><i class="fa fa-area-chart"></i></a></td><td>' . ucwords($jj['project']) . (($jj['version']) ? ' ' . $jj['version'] : '') . '</td>';
+ $o .= '<tr><td><a href="'. (($jj['sellpage']) ? $jj['sellpage'] : $jj['url'] . '/register' ) . '" ><i class="fa fa-link"></i> ' . $urltext . '</a>' . $location . '</td><td>' . $jj['access'] . '</td><td>' . $jj['register'] . '</td><!--td>' . '<a target="stats" href="https://hubchart-tarine.rhcloud.com/hub.jsp?hubFqdn=' . $m['host'] . '"><i class="fa fa-area-chart"></i></a></td--><td>' . ucwords($jj['project']) . (($jj['version']) ? ' ' . $jj['version'] : '') . '</td>';
if($rating_enabled)
$o .= '<td><a href="ratings/' . $host . '" class="btn-btn-default"><i class="fa fa-eye"></i> ' . t('View') . '</a></td>' . $rate_links ;
$o .= '</tr>';
diff --git a/Zotlabs/Module/Pubstream.php b/Zotlabs/Module/Pubstream.php
index 42aa2b51b..15e2d8a74 100644
--- a/Zotlabs/Module/Pubstream.php
+++ b/Zotlabs/Module/Pubstream.php
@@ -7,10 +7,10 @@ require_once('include/conversation.php');
class Pubstream extends \Zotlabs\Web\Controller {
function get($update = 0, $load = false) {
-
+
if($load)
$_SESSION['loadtime'] = datetime_convert();
-
+
if(observer_prohibited(true)) {
return login();
@@ -19,15 +19,28 @@ class Pubstream extends \Zotlabs\Web\Controller {
$disable_discover_tab = get_config('system','disable_discover_tab') || get_config('system','disable_discover_tab') === false;
if($disable_discover_tab)
return;
-
+
+ $mid = ((x($_REQUEST,'mid')) ? $_REQUEST['mid'] : '');
+
+ if(strpos($mid,'b64.') === 0)
+ $decoded = @base64url_decode(substr($mid,4));
+ if($decoded)
+ $mid = $decoded;
+
$item_normal = item_normal();
+ $item_normal_update = item_normal_update();
$static = ((array_key_exists('static',$_REQUEST)) ? intval($_REQUEST['static']) : 0);
- if(! $update) {
+ if(! $update && !$load) {
+
+ nav_set_selected(t('Public Stream'));
- $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 0);
+ if(!$mid)
+ $_SESSION['static_loadtime'] = datetime_convert();
+
+ $static = ((local_channel()) ? channel_manual_conv_update(local_channel()) : 1);
$maxheight = get_config('system','home_divmore_height');
if(! $maxheight)
@@ -38,6 +51,10 @@ class Pubstream extends \Zotlabs\Web\Controller {
. "; var profile_page = " . \App::$pager['page']
. "; divmore_height = " . intval($maxheight) . "; </script>\r\n";
+ //if we got a decoded hash we must encode it again before handing to javascript
+ if($decoded)
+ $mid = 'b64.' . base64url_encode($mid);
+
\App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array(
'$baseurl' => z_root(),
'$pgtype' => 'pubstream',
@@ -63,7 +80,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
'$cats' => '',
'$tags' => '',
'$dend' => '',
- '$mid' => '',
+ '$mid' => $mid,
'$verb' => '',
'$dbegin' => ''
));
@@ -105,7 +122,7 @@ class Pubstream extends \Zotlabs\Web\Controller {
$simple_update = '';
if($static && $simple_update)
- $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
+ $simple_update .= " and item_thread_top = 0 and author_xchan = '" . protect_sprintf(get_observer_hash()) . "' ";
//logger('update: ' . $update . ' load: ' . $load);
@@ -114,29 +131,46 @@ class Pubstream extends \Zotlabs\Web\Controller {
$ordering = "commented";
if($load) {
-
- // Fetch a page full of parent items for this page
-
- $r = q("SELECT distinct item.id AS item_id, $ordering FROM item
- left join abook on item.author_xchan = abook.abook_xchan
- WHERE true $uids $item_normal
- AND item.parent = item.id
- and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets
- ORDER BY $ordering DESC $pager_sql "
- );
-
-
+ if($mid) {
+ $r = q("SELECT parent AS item_id FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE mid like '%s' $uids $item_normal
+ and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra3 $sql_extra $sql_nets LIMIT 1",
+ dbesc($mid . '%')
+ );
+ }
+ else {
+ // Fetch a page full of parent items for this page
+ $r = q("SELECT distinct item.id AS item_id, $ordering FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE true $uids $item_normal
+ AND item.parent = item.id
+ and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra3 $sql_extra $sql_nets
+ ORDER BY $ordering DESC $pager_sql "
+ );
+ }
}
elseif($update) {
-
- $r = q("SELECT distinct item.id AS item_id, $ordering FROM item
- left join abook on item.author_xchan = abook.abook_xchan
- WHERE true $uids $item_normal
- AND item.parent = item.id $simple_update
- and (abook.abook_blocked = 0 or abook.abook_flags is null)
- $sql_extra3 $sql_extra $sql_nets"
- );
+ if($mid) {
+ $r = q("SELECT parent AS item_id FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE mid like '%s' $uids $item_normal_update $simple_update
+ and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra3 $sql_extra $sql_nets LIMIT 1",
+ dbesc($mid . '%')
+ );
+ }
+ else {
+ $r = q("SELECT distinct item.id AS item_id, $ordering FROM item
+ left join abook on item.author_xchan = abook.abook_xchan
+ WHERE true $uids $item_normal_update
+ AND item.parent = item.id $simple_update
+ and (abook.abook_blocked = 0 or abook.abook_flags is null)
+ $sql_extra3 $sql_extra $sql_nets"
+ );
+ }
$_SESSION['loadtime'] = datetime_convert();
}
// Then fetch all the children of the parents that are on this page
@@ -168,6 +202,9 @@ class Pubstream extends \Zotlabs\Web\Controller {
$mode = ('network');
$o .= conversation($items,$mode,$update,$page_mode);
+
+ if($mid)
+ $o .= '<div id="content-complete"></div>';
if(($items) && (! $update))
$o .= alt_pager($a,count($items));
diff --git a/Zotlabs/Module/Register.php b/Zotlabs/Module/Register.php
index d4573156c..95e3ca96f 100644
--- a/Zotlabs/Module/Register.php
+++ b/Zotlabs/Module/Register.php
@@ -27,7 +27,7 @@ class Register extends \Zotlabs\Web\Controller {
$result = check_account_email($_REQUEST['email']);
break;
case 'password_check.json':
- $result = check_account_password($_REQUEST['password']);
+ $result = check_account_password($_REQUEST['password1']);
break;
default:
break;
@@ -123,12 +123,19 @@ class Register extends \Zotlabs\Web\Controller {
if($policy == REGISTER_OPEN ) {
if($email_verify) {
$res = verify_email_address($result);
+ if($res) {
+ info( t('Registration successful. Please check your email for validation instructions.') . EOL ) ;
+ }
}
else {
$res = send_register_success_email($result['email'],$result['password']);
}
if($res) {
- info( t('Registration successful. Please check your email for validation instructions.') . EOL ) ;
+ if($invite_code) {
+ info( t('Registration successful. Continue to create your first channel...') . EOL ) ;
+ } else {
+ info( t('Registration successful. Please check your email for validation instructions.') . EOL ) ;
+ }
}
}
elseif($policy == REGISTER_APPROVE) {
@@ -167,7 +174,8 @@ class Register extends \Zotlabs\Web\Controller {
$next_page = $x;
$_SESSION['workflow'] = true;
}
-
+
+ unset($_SESSION['login_return_url']);
goaway(z_root() . '/' . $next_page);
}
@@ -231,8 +239,8 @@ class Register extends \Zotlabs\Web\Controller {
$enable_tos = 1 - intval(get_config('system','no_termsofservice'));
$email = array('email', t('Your email address'), ((x($_REQUEST,'email')) ? strip_tags(trim($_REQUEST['email'])) : ""));
- $password = array('password', t('Choose a password'), ((x($_REQUEST,'password')) ? trim($_REQUEST['password']) : ""));
- $password2 = array('password2', t('Please re-enter your password'), ((x($_REQUEST,'password2')) ? trim($_REQUEST['password2']) : ""));
+ $password = array('password', t('Choose a password'), '');
+ $password2 = array('password2', t('Please re-enter your password'), '');
$invite_code = array('invite_code', t('Please enter your invitation code'), ((x($_REQUEST,'invite_code')) ? strip_tags(trim($_REQUEST['invite_code'])) : ""));
$name = array('name', t('Name or caption'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"'));
$nickhub = '@' . str_replace(array('http://','https://','/'), '', get_config('system','baseurl'));
diff --git a/Zotlabs/Module/Rmagic.php b/Zotlabs/Module/Rmagic.php
index 9fcc72441..bfc03f6ec 100644
--- a/Zotlabs/Module/Rmagic.php
+++ b/Zotlabs/Module/Rmagic.php
@@ -17,8 +17,8 @@ class Rmagic extends \Zotlabs\Web\Controller {
if($r) {
if($r[0]['hubloc_url'] === z_root())
goaway(z_root() . '/login');
- $dest = z_root() . '/' . str_replace('zid=','zid_=',\App::$query_string);
- goaway($r[0]['hubloc_url'] . '/magic' . '?f=&dest=' . $dest);
+ $dest = z_root() . '/' . str_replace(['rmagic','zid='],['','zid_='],\App::$query_string);
+ goaway($r[0]['hubloc_url'] . '/magic' . '?f=&owa=1&dest=' . $dest);
}
}
}
@@ -61,9 +61,9 @@ class Rmagic extends \Zotlabs\Web\Controller {
if($_SESSION['return_url'])
$dest = urlencode(z_root() . '/' . str_replace('zid=','zid_=',$_SESSION['return_url']));
else
- $dest = urlencode(z_root() . '/' . str_replace('zid=','zid_=',\App::$query_string));
+ $dest = urlencode(z_root() . '/' . str_replace([ 'rmagic', 'zid=' ] ,[ '', 'zid_='],\App::$query_string));
- goaway($url . '/magic' . '?f=&dest=' . $dest);
+ goaway($url . '/magic' . '?f=&owa=1&dest=' . $dest);
}
}
}
diff --git a/Zotlabs/Module/Rpost.php b/Zotlabs/Module/Rpost.php
index 731eab82e..5d2f0d7e8 100644
--- a/Zotlabs/Module/Rpost.php
+++ b/Zotlabs/Module/Rpost.php
@@ -20,6 +20,7 @@ require_once('include/zot.php');
* body= Body of post
* url= URL which will be parsed and the results appended to the body
* source= Source application
+ * post_id= post_id of post to 'share' (local use only)
* remote_return= absolute URL to return after posting is finished
* type= choices are 'html' or 'bbcode', default is 'bbcode'
*
@@ -60,7 +61,7 @@ class Rpost extends \Zotlabs\Web\Controller {
return login();
}
- nav_set_selected(t('Post'));
+ nav_set_selected('Post');
// If we have saved rpost session variables, but nothing in the current $_REQUEST, recover the saved variables
@@ -90,8 +91,6 @@ class Rpost extends \Zotlabs\Web\Controller {
}
$plaintext = true;
- // if(feature_enabled(local_channel(),'richtext'))
- // $plaintext = false;
if(array_key_exists('type', $_REQUEST) && $_REQUEST['type'] === 'html') {
require_once('include/html2bbcode.php');
@@ -110,28 +109,67 @@ class Rpost extends \Zotlabs\Web\Controller {
if($x['success'])
$_REQUEST['body'] = $_REQUEST['body'] . $x['body'];
}
+
+ if($_REQUEST['post_id']) {
+ $r = q("SELECT * from item WHERE id = %d LIMIT 1",
+ intval($_REQUEST['post_id'])
+ );
+ if(($r) && (! intval($r[0]['item_private']))) {
+ $sql_extra = item_permissions_sql($r[0]['uid']);
+
+ $r = q("select * from item where id = %d $sql_extra",
+ intval($_REQUEST['post_id'])
+ );
+ if($r && $r[0]['mimetype'] === 'text/bbcode') {
+
+ xchan_query($r);
+
+ $is_photo = (($r[0]['obj_type'] === ACTIVITY_OBJ_PHOTO) ? true : false);
+ if($is_photo) {
+ $object = json_decode($r[0]['obj'],true);
+ $photo_bb = $object['body'];
+ }
+
+ if (strpos($r[0]['body'], "[/share]") !== false) {
+ $pos = strpos($r[0]['body'], "[share");
+ $i = substr($r[0]['body'], $pos);
+ } else {
+ $i = "[share author='".urlencode($r[0]['author']['xchan_name']).
+ "' profile='".$r[0]['author']['xchan_url'] .
+ "' avatar='".$r[0]['author']['xchan_photo_s'].
+ "' link='".$r[0]['plink'].
+ "' posted='".$r[0]['created'].
+ "' message_id='".$r[0]['mid']."']";
+ if($r[0]['title'])
+ $i .= '[b]'.$r[0]['title'].'[/b]'."\r\n";
+ $i .= (($is_photo) ? $photo_bb . "\r\n" . $r[0]['body'] : $r[0]['body']);
+ $i .= "[/share]";
+ }
+ }
+ }
+ $_REQUEST['body'] = $_REQUEST['body'] . $i;
+ }
$x = array(
- 'is_owner' => true,
- 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''),
- 'default_location' => $channel['channel_location'],
- 'nickname' => $channel['channel_address'],
- 'lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'),
- 'acl' => populate_acl($channel_acl, true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
- 'permissions' => $channel_acl,
- 'bang' => '',
- 'visitor' => true,
- 'profile_uid' => local_channel(),
- 'title' => $_REQUEST['title'],
- 'body' => $_REQUEST['body'],
- 'attachment' => $_REQUEST['attachment'],
- 'source' => ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''),
- 'return_path' => 'rpost/return',
- 'bbco_autocomplete' => 'bbcode',
- 'editor_autocomplete'=> true,
- 'bbcode' => true,
- 'jotnets' => true
-
+ 'is_owner' => true,
+ 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''),
+ 'default_location' => $channel['channel_location'],
+ 'nickname' => $channel['channel_address'],
+ 'lockstate' => (($acl->is_private()) ? 'lock' : 'unlock'),
+ 'acl' => populate_acl($channel_acl, true, \Zotlabs\Lib\PermissionDescription::fromGlobalPermission('view_stream'), get_post_aclDialogDescription(), 'acl_dialog_post'),
+ 'permissions' => $channel_acl,
+ 'bang' => '',
+ 'visitor' => true,
+ 'profile_uid' => local_channel(),
+ 'title' => $_REQUEST['title'],
+ 'body' => $_REQUEST['body'],
+ 'attachment' => $_REQUEST['attachment'],
+ 'source' => ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''),
+ 'return_path' => 'rpost/return',
+ 'bbco_autocomplete' => 'bbcode',
+ 'editor_autocomplete' => true,
+ 'bbcode' => true,
+ 'jotnets' => true
);
$editor = status_editor($a,$x);
diff --git a/Zotlabs/Module/Search.php b/Zotlabs/Module/Search.php
index e1d35b879..37e9a336f 100644
--- a/Zotlabs/Module/Search.php
+++ b/Zotlabs/Module/Search.php
@@ -22,7 +22,7 @@ class Search extends \Zotlabs\Web\Controller {
if($load)
$_SESSION['loadtime'] = datetime_convert();
- nav_set_selected(t('Search'));
+ nav_set_selected('Search');
require_once("include/bbcode.php");
require_once('include/security.php');
diff --git a/Zotlabs/Module/Settings/Channel.php b/Zotlabs/Module/Settings/Channel.php
index 3e6adcf8d..41e23b717 100644
--- a/Zotlabs/Module/Settings/Channel.php
+++ b/Zotlabs/Module/Settings/Channel.php
@@ -199,6 +199,10 @@ class Channel {
$vnotify += intval($_POST['vnotify10']);
if(x($_POST,'vnotify11'))
$vnotify += intval($_POST['vnotify11']);
+ if(x($_POST,'vnotify12'))
+ $vnotify += intval($_POST['vnotify12']);
+ if(x($_POST,'vnotify13') && (get_config('system', 'disable_discover_tab') != 1))
+ $vnotify += intval($_POST['vnotify13']);
$always_show_in_notices = x($_POST,'always_show_in_notices') ? 1 : 0;
@@ -505,7 +509,7 @@ class Channel {
'$expire' => array('expire',t('Expire other channel content after this many days'),$expire, t('0 or blank to use the website limit.') . ' ' . ((intval($sys_expire)) ? sprintf( t('This website expires after %d days.'),intval($sys_expire)) : t('This website does not expire imported content.')) . ' ' . t('The website limit takes precedence if lower than your limit.')),
'$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')),
- '$permissions' => t('Default Access Control List (ACL)'),
+ '$permissions' => t('Default Privacy Group'),
'$permdesc' => t("\x28click to open/close\x29"),
'$aclselect' => populate_acl($perm_defaults, false, \Zotlabs\Lib\PermissionDescription::fromDescription(t('Use my default audience setting for the type of object published'))),
'$allow_cid' => acl2json($perm_defaults['allow_cid']),
@@ -555,6 +559,8 @@ class Channel {
'$vnotify9' => array('vnotify9', t('System critical alerts'), ($vnotify & VNOTIFY_ALERT), VNOTIFY_ALERT, t('Recommended'), $yes_no),
'$vnotify10' => array('vnotify10', t('New connections'), ($vnotify & VNOTIFY_INTRO), VNOTIFY_INTRO, t('Recommended'), $yes_no),
'$vnotify11' => array('vnotify11', t('System Registrations'), ($vnotify & VNOTIFY_REGISTER), VNOTIFY_REGISTER, '', $yes_no),
+ '$vnotify12' => array('vnotify12', t('Unseen shared files'), ($vnotify & VNOTIFY_FILES), VNOTIFY_FILES, '', $yes_no),
+ '$vnotify13' => ((get_config('system', 'disable_discover_tab') != 1) ? array('vnotify13', t('Unseen public activity'), ($vnotify & VNOTIFY_PUBS), VNOTIFY_PUBS, '', $yes_no) : array()),
'$always_show_in_notices' => array('always_show_in_notices', t('Also show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no),
'$evdays' => array('evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')),
diff --git a/Zotlabs/Module/Suggest.php b/Zotlabs/Module/Suggest.php
index c3f4a6d5a..f79e4e245 100644
--- a/Zotlabs/Module/Suggest.php
+++ b/Zotlabs/Module/Suggest.php
@@ -29,7 +29,7 @@ class Suggest extends \Zotlabs\Web\Controller {
return;
}
- nav_set_selected(t('Suggest Channels'));
+ nav_set_selected('Suggest Channels');
$_SESSION['return_url'] = z_root() . '/' . \App::$cmd;
diff --git a/Zotlabs/Module/Tasks.php b/Zotlabs/Module/Tasks.php
index c8deb11bf..0709f31f6 100644
--- a/Zotlabs/Module/Tasks.php
+++ b/Zotlabs/Module/Tasks.php
@@ -19,8 +19,8 @@ class Tasks extends \Zotlabs\Web\Controller {
$arr['all'] = 1;
$x = tasks_fetch($arr);
+ $x['html'] = '';
if($x['tasks']) {
- $x['html'] = '';
foreach($x['tasks'] as $y) {
$x['html'] .= '<div class="tasklist-item"><input type="checkbox" onchange="taskComplete(' . $y['id'] . '); return false;" /> ' . $y['summary'] . '</div>';
}
@@ -69,6 +69,7 @@ class Tasks extends \Zotlabs\Web\Controller {
if($x)
$ret['success'] = true;
}
+
json_return_and_die($ret);
}
diff --git a/Zotlabs/Module/Thing.php b/Zotlabs/Module/Thing.php
index 95c6c5636..f816632ab 100644
--- a/Zotlabs/Module/Thing.php
+++ b/Zotlabs/Module/Thing.php
@@ -91,6 +91,7 @@ class Thing extends \Zotlabs\Web\Controller {
}
$orig_record = $t[0];
if($photo != $orig_record['obj_imgurl']) {
+ delete_thing_photo($orig_record['obj_imgurl'],get_observer_hash());
$arr = import_xchan_photo($photo,get_observer_hash(),true);
$local_photo = $arr[0];
$local_photo_type = $arr[3];
@@ -336,6 +337,9 @@ class Thing extends \Zotlabs\Web\Controller {
return '';
}
+
+ delete_thing_photo($r[0]['obj_imgurl'],get_observer_hash());
+
$x = q("delete from obj where obj_obj = '%s' and obj_type = %d and obj_channel = %d",
dbesc($thing_hash),
intval(TERM_OBJ_THING),
diff --git a/Zotlabs/Module/Update_cards.php b/Zotlabs/Module/Update_cards.php
new file mode 100644
index 000000000..bb87357e8
--- /dev/null
+++ b/Zotlabs/Module/Update_cards.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Zotlabs\Module;
+
+/**
+ * Module: update_profile
+ * Purpose: AJAX synchronisation of profile page
+ *
+ */
+
+
+class Update_cards extends \Zotlabs\Web\Controller {
+
+function get() {
+
+ $profile_uid = intval($_GET['p']);
+ $load = (((argc() > 1) && (argv(1) == 'load')) ? 1 : 0);
+
+ header("Content-type: text/html");
+ echo "<!DOCTYPE html><html><body><section></section></body></html>\r\n";
+
+ killme();
+
+
+ $mod = new Cards();
+
+ $text = $mod->get($profile_uid,$load);
+
+ /**
+ * reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well
+ */
+
+ echo str_replace("\t",' ',$text);
+ echo (($_GET['msie'] == 1) ? '</div>' : '</section>');
+ echo "</body></html>\r\n";
+ killme();
+
+}
+}
diff --git a/Zotlabs/Module/Wall_attach.php b/Zotlabs/Module/Wall_attach.php
index 03d4cb37b..e001ad929 100644
--- a/Zotlabs/Module/Wall_attach.php
+++ b/Zotlabs/Module/Wall_attach.php
@@ -97,6 +97,12 @@ class Wall_attach extends \Zotlabs\Web\Controller {
$s = "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n";
}
+
+ $sync = attach_export_data($channel,$r['data']['hash']);
+ if($sync) {
+ build_sync_packet($channel['channel_id'],array('file' => array($sync)));
+ }
+
if($using_api)
return $s;
diff --git a/Zotlabs/Module/Webpages.php b/Zotlabs/Module/Webpages.php
index e449a790f..97ec55ba3 100644
--- a/Zotlabs/Module/Webpages.php
+++ b/Zotlabs/Module/Webpages.php
@@ -35,7 +35,7 @@ class Webpages extends \Zotlabs\Web\Controller {
return;
}
- nav_set_selected(t('Webpages'));
+ nav_set_selected('Webpages');
$which = argv(1);
diff --git a/Zotlabs/Module/Wfinger.php b/Zotlabs/Module/Wfinger.php
index 07a7b7735..2e9307196 100644
--- a/Zotlabs/Module/Wfinger.php
+++ b/Zotlabs/Module/Wfinger.php
@@ -30,9 +30,15 @@ class Wfinger extends \Zotlabs\Web\Controller {
$resource = $_REQUEST['resource'];
logger('webfinger: ' . $resource,LOGGER_DEBUG);
+
+ $root_resource = false;
+
+ if(strcasecmp(rtrim($resource,'/'),z_root()) === 0)
+ $root_resource = true;
+
$r = null;
- if($resource) {
+ if(($resource) && (! $root_resource)) {
if(strpos($resource,'acct:') === 0) {
$channel = str_replace('acct:','',$resource);
@@ -60,7 +66,25 @@ class Wfinger extends \Zotlabs\Web\Controller {
header('Access-Control-Allow-Origin: *');
+
+ if($root_resource) {
+ $result['subject'] = $resource;
+ $result['properties'] = [
+ 'https://w3id.org/security/v1#publicKeyPem' => get_config('system','pubkey')
+ ];
+ $result['links'] = [
+ [
+ 'rel' => 'http://purl.org/openwebauth/v1',
+ 'type' => 'application/x-zot+json',
+ 'href' => z_root() . '/owa',
+ ],
+ ];
+
+
+
+ }
+
if($resource && $r) {
$h = q("select hubloc_addr from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0",
@@ -84,7 +108,8 @@ class Wfinger extends \Zotlabs\Web\Controller {
$result['properties'] = [
'http://webfinger.net/ns/name' => $r[0]['channel_name'],
- 'http://xmlns.com/foaf/0.1/name' => $r[0]['channel_name']
+ 'http://xmlns.com/foaf/0.1/name' => $r[0]['channel_name'],
+ 'https://w3id.org/security/v1#publicKeyPem' => $r[0]['xchan_pubkey']
];
foreach($aliases as $alias)
@@ -98,7 +123,13 @@ class Wfinger extends \Zotlabs\Web\Controller {
'type' => $r[0]['xchan_photo_mimetype'],
'href' => $r[0]['xchan_photo_l']
],
-
+
+ [
+ 'rel' => 'http://microformats.org/profile/hcard',
+ 'type' => 'text/html',
+ 'href' => z_root() . '/hcard/' . $r[0]['channel_address']
+ ],
+
[
'rel' => 'http://webfinger.net/rel/profile-page',
'href' => z_root() . '/profile/' . $r[0]['channel_address'],
@@ -124,6 +155,13 @@ class Wfinger extends \Zotlabs\Web\Controller {
'rel' => 'http://purl.org/zot/protocol',
'href' => z_root() . '/.well-known/zot-info' . '?address=' . $r[0]['xchan_addr'],
],
+
+ [
+ 'rel' => 'http://purl.org/openwebauth/v1',
+ 'type' => 'application/x-zot+json',
+ 'href' => z_root() . '/owa',
+ ],
+
[
'rel' => 'magic-public-key',
@@ -136,14 +174,16 @@ class Wfinger extends \Zotlabs\Web\Controller {
$result['zot'] = zotinfo( [ 'address' => $r[0]['xchan_addr'] ]);
}
}
- else {
+
+ if(! $result) {
header($_SERVER["SERVER_PROTOCOL"] . ' ' . 400 . ' ' . 'Bad Request');
killme();
}
$arr = [ 'channel' => $r[0], 'request' => $_REQUEST, 'result' => $result ];
call_hooks('webfinger',$arr);
-
+
+
json_return_and_die($arr['result'],'application/jrd+json');
}
diff --git a/Zotlabs/Module/Wiki.php b/Zotlabs/Module/Wiki.php
index 4dc11c683..d6a01af11 100644
--- a/Zotlabs/Module/Wiki.php
+++ b/Zotlabs/Module/Wiki.php
@@ -76,7 +76,7 @@ class Wiki extends \Zotlabs\Web\Controller {
$wiki_owner = true;
- nav_set_selected(t('Wiki'));
+ nav_set_selected('Wiki');
// Obtain the default permission settings of the channel
$owner_acl = array(
@@ -113,12 +113,13 @@ class Wiki extends \Zotlabs\Web\Controller {
$o = '';
// Download a wiki
-/*
+
if((argc() > 3) && (argv(2) === 'download') && (argv(3) === 'wiki')) {
$resource_id = argv(4);
+ $w = Zlib\NativeWiki::get_wiki($owner['channel_id'],$observer_hash,$resource_id);
- $w = Zlib\NativeWiki::get_wiki($owner,$observer_hash,$resource_id);
+// $w = Zlib\NativeWiki::get_wiki($owner,$observer_hash,$resource_id);
if(! $w['htmlName']) {
notice(t('Error retrieving wiki') . EOL);
}
@@ -133,8 +134,41 @@ class Wiki extends \Zotlabs\Web\Controller {
$zip_filename = $w['urlName'];
$zip_filepath = '/tmp/' . $zip_folder_name . '/' . $zip_filename;
+
// Generate the zip file
- ZLib\ExtendedZip::zipTree($w['path'], $zip_filepath, \ZipArchive::CREATE);
+
+ $zip = new \ZipArchive;
+ $r = $zip->open($zip_filepath, \ZipArchive::CREATE);
+ if($r === true) {
+ $pages = [];
+ $i = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s' order by revision desc",
+ dbesc($resource_id)
+ );
+
+ if($i) {
+ foreach($i as $iv) {
+ if(in_array($iv['mid'],$pages))
+ continue;
+
+ if($iv['mimetype'] === 'text/plain') {
+ $content = html_entity_decode($iv['body'],ENT_COMPAT,'UTF-8');
+ }
+ elseif($iv['mimetype'] === 'text/bbcode') {
+ $content = html_entity_decode($iv['body'],ENT_COMPAT,'UTF-8');
+ }
+ elseif($iv['mimetype'] === 'text/markdown') {
+ $content = html_entity_decode(Zlib\MarkdownSoap::unescape($iv['body']),ENT_COMPAT,'UTF-8');
+ }
+ $fname = get_iconfig($iv['id'],'nwikipage','pagetitle') . Zlib\NativeWikiPage::get_file_ext($iv);
+ $zip->addFromString($fname,$content);
+ $pages[] = $iv['mid'];
+ }
+
+
+ }
+
+ }
+ $zip->close();
// Output the file for download
@@ -153,10 +187,11 @@ class Wiki extends \Zotlabs\Web\Controller {
killme();
}
-*/
+
switch(argc()) {
case 2:
$wikis = Zlib\NativeWiki::listwikis($owner, get_observer_hash());
+
if($wikis) {
$o .= replace_macros(get_markup_template('wikilist.tpl'), array(
'$header' => t('Wikis'),
@@ -170,16 +205,19 @@ class Wiki extends \Zotlabs\Web\Controller {
'$create' => t('Create New'),
'$submit' => t('Submit'),
'$wikiName' => array('wikiName', t('Wiki name')),
- '$mimeType' => array('mimeType', t('Content type'), '', '', ['text/markdown' => 'Markdown', 'text/bbcode' => 'BB Code']),
+ '$mimeType' => array('mimeType', t('Content type'), '', '', ['text/markdown' => t('Markdown'), 'text/bbcode' => t('BBcode'), 'text/plain' => t('Text') ]),
'$name' => t('Name'),
'$type' => t('Type'),
+ '$unlocked' => t('Any&nbsp;type'),
'$lockstate' => $x['lockstate'],
'$acl' => $x['acl'],
'$allow_cid' => $x['allow_cid'],
'$allow_gid' => $x['allow_gid'],
'$deny_cid' => $x['deny_cid'],
'$deny_gid' => $x['deny_gid'],
- '$notify' => array('postVisible', t('Create a status post for this wiki'), '', '', array(t('No'), t('Yes')))
+ '$typelock' => array('typelock', t('Lock content type'), '', '', array(t('No'), t('Yes'))),
+ '$notify' => array('postVisible', t('Create a status post for this wiki'), '', '', array(t('No'), t('Yes'))),
+ '$edit_wiki_name' => t('Edit Wiki Name')
));
return $o;
@@ -259,9 +297,11 @@ class Wiki extends \Zotlabs\Web\Controller {
goaway(z_root() . '/' . argv(0) . '/' . argv(1) );
}
- $mimeType = $p['mimeType'];
+ $mimeType = $p['pageMimeType'];
$sampleContent = (($mimeType == 'text/bbcode') ? '[h3]' . t('New page') . '[/h3]' : '### ' . t('New page'));
+ if($mimeType === 'text/plain')
+ $sampleContent = t('New page');
$content = (($p['content'] == '') ? $sampleContent : $p['content']);
@@ -269,7 +309,10 @@ class Wiki extends \Zotlabs\Web\Controller {
if($mimeType == 'text/bbcode') {
$renderedContent = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))), argv(0) . '/' . argv(1) . '/' . $wikiUrlName);
}
- else {
+ elseif($mimeType === 'text/plain') {
+ $renderedContent = str_replace(["\n",' ',"\t"],[EOL,'&nbsp;','&nbsp;&nbsp;&nbsp;&nbsp;'],htmlentities($content,ENT_COMPAT,'UTF-8',false));
+ }
+ elseif($mimeType === 'text/markdown') {
$content = Zlib\MarkdownSoap::unescape($content);
$html = Zlib\NativeWikiPage::generate_toc(zidify_text(MarkdownExtra::defaultTransform(Zlib\NativeWikiPage::bbcode($content))));
$renderedContent = Zlib\NativeWikiPage::convert_links($html, argv(0) . '/' . argv(1) . '/' . $wikiUrlName);
@@ -290,6 +333,9 @@ class Wiki extends \Zotlabs\Web\Controller {
'$cancel' => t('Cancel')
));
+ $types = [ 'text/bbcode' => t('BBcode'), 'text/markdown' => t('Markdown'), 'text/plain' => 'Text' ];
+ $currenttype = $types[$mimeType];
+
$placeholder = t('Short description of your changes (optional)');
$o .= replace_macros(get_markup_template('wiki.tpl'),array(
@@ -304,6 +350,7 @@ class Wiki extends \Zotlabs\Web\Controller {
'$resource_id' => $resource_id,
'$page' => $pageUrlName,
'$mimeType' => $mimeType,
+ '$typename' => $currenttype,
'$content' => $content,
'$renderedContent' => $renderedContent,
'$pageRename' => array('pageRename', t('New page name'), '', ''),
@@ -323,7 +370,7 @@ class Wiki extends \Zotlabs\Web\Controller {
'$modalerroralbum' => t('Error getting album'),
));
- if($p['mimeType'] != 'text/bbcode')
+ if($p['pageMimeType'] === 'text/markdown')
head_add_js('/library/ace/ace.js'); // Ace Code Editor
return $o;
@@ -347,17 +394,17 @@ class Wiki extends \Zotlabs\Web\Controller {
if((argc() > 2) && (argv(2) === 'preview')) {
$content = $_POST['content'];
$resource_id = $_POST['resource_id'];
+
$w = Zlib\NativeWiki::get_wiki($owner['channel_id'],$observer_hash,$resource_id);
$wikiURL = argv(0) . '/' . argv(1) . '/' . $w['urlName'];
- $mimeType = $w['mimeType'];
+ $mimeType = $_POST['mimetype'];
- if($mimeType == 'text/bbcode') {
+ if($mimeType === 'text/bbcode') {
$html = Zlib\NativeWikiPage::convert_links(zidify_links(smilies(bbcode($content))),$wikiURL);
}
- else {
-
+ elseif($mimeType === 'text/markdown') {
$bb = Zlib\NativeWikiPage::bbcode($content);
$x = new ZLib\MarkdownSoap($bb);
$md = $x->clean();
@@ -366,6 +413,9 @@ class Wiki extends \Zotlabs\Web\Controller {
$html = Zlib\NativeWikiPage::generate_toc(zidify_text($html));
$html = Zlib\NativeWikiPage::convert_links($html,$wikiURL);
}
+ elseif($mimeType === 'text/plain') {
+ $html = str_replace(["\n",' ',"\t"],[EOL,'&nbsp;','&nbsp;&nbsp;&nbsp;&nbsp;'],htmlentities($content,ENT_COMPAT,'UTF-8',false));
+ }
json_return_and_die(array('html' => $html, 'success' => true));
}
@@ -386,6 +436,7 @@ class Wiki extends \Zotlabs\Web\Controller {
$wiki['htmlName'] = escape_tags($_POST['wikiName']);
$wiki['urlName'] = urlencode(urlencode($_POST['wikiName']));
$wiki['mimeType'] = $_POST['mimeType'];
+ $wiki['typelock'] = $_POST['typelock'];
if($wiki['urlName'] === '') {
notice( t('Error creating wiki. Invalid name.') . EOL);
@@ -406,7 +457,7 @@ class Wiki extends \Zotlabs\Web\Controller {
$r = Zlib\NativeWiki::create_wiki($owner, $observer_hash, $wiki, $acl);
if($r['success']) {
Zlib\NativeWiki::sync_a_wiki_item($owner['channel_id'],$r['item_id'],$r['item']['resource_id']);
- $homePage = Zlib\NativeWikiPage::create_page($owner['channel_id'],$observer_hash,'Home', $r['item']['resource_id']);
+ $homePage = Zlib\NativeWikiPage::create_page($owner['channel_id'],$observer_hash,'Home', $r['item']['resource_id'], $wiki['mimeType']);
if(! $homePage['success']) {
notice( t('Wiki created, but error creating Home page.'));
goaway(z_root() . '/wiki/' . $nick . '/' . $wiki['urlName']);
@@ -420,6 +471,52 @@ class Wiki extends \Zotlabs\Web\Controller {
}
}
+ // Update a wiki
+ // /wiki/channel/update/wiki
+ if ((argc() > 3) && (argv(2) === 'update') && (argv(3) === 'wiki')) {
+ // Only the channel owner can update a wiki, at least until we create a
+ // more detail permissions framework
+
+ if (local_channel() !== intval($owner['channel_id'])) {
+ goaway('/' . argv(0) . '/' . $nick . '/');
+ }
+
+ $arr = [];
+
+ $arr['urlName'] = urlencode(urlencode($_POST['origRawName']));
+
+ if($_POST['updateRawName'])
+ $arr['updateRawName'] = $_POST['updateRawName'];
+
+ if(($arr['urlName'] || $arr['updateRawName']) === '') {
+ notice( t('Error updating wiki. Invalid name.') . EOL);
+ goaway('/wiki');
+ return; //not reached
+ }
+
+ $wiki = Zlib\NativeWiki::exists_by_name($owner['channel_id'], $arr['urlName']);
+
+ if($wiki['resource_id']) {
+
+ $arr['resource_id'] = $wiki['resource_id'];
+
+ $acl = new \Zotlabs\Access\AccessList($owner);
+ $acl->set_from_array($_POST);
+
+ $r = Zlib\NativeWiki::update_wiki($owner['channel_id'], $observer_hash, $arr, $acl);
+ if($r['success']) {
+ Zlib\NativeWiki::sync_a_wiki_item($owner['channel_id'],$r['item_id'],$r['item']['resource_id']);
+ goaway(z_root() . '/wiki/' . $nick);
+ }
+ else {
+ notice( t('Error updating wiki'));
+ goaway(z_root() . '/wiki');
+ }
+
+ }
+ goaway(z_root() . '/wiki');
+ }
+
// Delete a wiki
if ((argc() > 3) && (argv(2) === 'delete') && (argv(3) === 'wiki')) {
@@ -445,11 +542,13 @@ class Wiki extends \Zotlabs\Web\Controller {
// Create a page
if ((argc() === 4) && (argv(2) === 'create') && (argv(3) === 'page')) {
+ $mimetype = $_POST['mimetype'];
+
$resource_id = $_POST['resource_id'];
// Determine if observer has permission to create a page
+
-
- $perms = Zlib\NativeWiki::get_permissions($resource_id, intval($owner['channel_id']), $observer_hash);
+ $perms = Zlib\NativeWiki::get_permissions($resource_id, intval($owner['channel_id']), $observer_hash, $mimetype);
if(! $perms['write']) {
logger('Wiki write permission denied. ' . EOL);
json_return_and_die(array('success' => false));
@@ -459,7 +558,7 @@ class Wiki extends \Zotlabs\Web\Controller {
if(urlencode(escape_tags($_POST['pageName'])) === '') {
json_return_and_die(array('message' => 'Error creating page. Invalid name.', 'success' => false));
}
- $page = Zlib\NativeWikiPage::create_page($owner['channel_id'],$observer_hash, $name, $resource_id);
+ $page = Zlib\NativeWikiPage::create_page($owner['channel_id'],$observer_hash, $name, $resource_id, $mimetype);
if($page['item_id']) {
$commit = Zlib\NativeWikiPage::commit(array(
diff --git a/Zotlabs/Module/Xrd.php b/Zotlabs/Module/Xrd.php
index 60a8f58fa..959e31cbe 100644
--- a/Zotlabs/Module/Xrd.php
+++ b/Zotlabs/Module/Xrd.php
@@ -50,6 +50,7 @@ class Xrd extends \Zotlabs\Web\Controller {
'$accturi' => $resource,
'$subject' => $subject,
'$aliases' => $aliases,
+ '$channel_url' => z_root() . '/channel/' . $r[0]['channel_address'],
'$profile_url' => z_root() . '/channel/' . $r[0]['channel_address'],
'$hcard_url' => z_root() . '/hcard/' . $r[0]['channel_address'],
'$atom' => z_root() . '/ofeed/' . $r[0]['channel_address'],
diff --git a/Zotlabs/Module/Zfinger.php b/Zotlabs/Module/Zfinger.php
index 2ff605fc9..0f7f6a64b 100644
--- a/Zotlabs/Module/Zfinger.php
+++ b/Zotlabs/Module/Zfinger.php
@@ -9,8 +9,36 @@ class Zfinger extends \Zotlabs\Web\Controller {
require_once('include/zot.php');
require_once('include/crypto.php');
-
$x = zotinfo($_REQUEST);
+
+ if($x && $x['guid'] && $x['guid_sig']) {
+ $chan_hash = make_xchan_hash($x['guid'],$x['guid_sig']);
+ if($chan_hash) {
+ $chan = channelx_by_hash($chan_hash);
+ }
+ }
+
+ $headers = [];
+ $headers['Content-Type'] = 'application/json' ;
+ $ret = json_encode($x);
+
+ if($chan) {
+ $hash = \Zotlabs\Web\HTTPSig::generate_digest($ret,false);
+ $headers['Digest'] = 'SHA-256=' . $hash;
+ \Zotlabs\Web\HTTPSig::create_sig('',$headers,$chan['channel_prvkey'],
+ 'acct:' . $chan['channel_address'] . '@' . \App::get_hostname(),true);
+ }
+ else {
+ foreach($headers as $k => $v) {
+ header($k . ': ' . $v);
+ }
+ }
+
+ echo $ret;
+ killme();
+
+
+
json_return_and_die($x);
}
diff --git a/Zotlabs/Render/Comanche.php b/Zotlabs/Render/Comanche.php
index beee9796e..8831bd117 100644
--- a/Zotlabs/Render/Comanche.php
+++ b/Zotlabs/Render/Comanche.php
@@ -121,6 +121,11 @@ class Comanche {
if($cnt)
\App::$layout['theme'] = trim($matches[1]);
+ $cnt = preg_match("/\[navbar\](.*?)\[\/navbar\]/ism", $s, $matches);
+ if($cnt)
+ \App::$layout['navbar'] = trim($matches[1]);
+
+
$cnt = preg_match_all("/\[webpage\](.*?)\[\/webpage\]/ism", $s, $matches, PREG_SET_ORDER);
if($cnt) {
// only the last webpage definition is used if there is more than one
@@ -148,6 +153,7 @@ class Comanche {
* $observer.address - xchan_addr or false
* $observer.name - xchan_name or false
* $observer - xchan_hash of observer or empty string
+ * $local_channel - logged in channel_id or false
*/
function get_condition_var($v) {
@@ -157,6 +163,9 @@ class Comanche {
return get_config($x[1],$x[2]);
elseif($x[0] === 'request')
return $_SERVER['REQUEST_URI'];
+ elseif($x[0] === 'local_channel') {
+ return local_channel();
+ }
elseif($x[0] === 'observer') {
if(count($x) > 1) {
if($x[1] == 'language')
@@ -168,6 +177,8 @@ class Comanche {
return $y['xchan_addr'];
elseif($x[1] == 'name')
return $y['xchan_name'];
+ elseif($x[1] == 'webname')
+ return substr($y['xchan_addr'],0,strpos($y['xchan_addr'],'@'));
return false;
}
return get_observer_hash();
@@ -450,6 +461,9 @@ class Comanche {
}
}
+ if(! purify_filename($name))
+ return '';
+
$clsname = ucfirst($name);
$nsname = "\\Zotlabs\\Widget\\" . $clsname;
diff --git a/Zotlabs/Storage/Browser.php b/Zotlabs/Storage/Browser.php
index 3af9fcab1..6f6f4a292 100644
--- a/Zotlabs/Storage/Browser.php
+++ b/Zotlabs/Storage/Browser.php
@@ -244,7 +244,7 @@ class Browser extends DAV\Browser\Plugin {
$a = false;
- nav_set_selected(t('Files'));
+ nav_set_selected('Files');
\App::$page['content'] = $html;
load_pdl();
@@ -347,7 +347,8 @@ class Browser extends DAV\Browser\Plugin {
'$return_url' => \App::$cmd,
'$path' => $path,
'$folder' => find_folder_hash_by_path($this->auth->owner_id, $path),
- '$dragdroptext' => t('Drop files here to immediately upload')
+ '$dragdroptext' => t('Drop files here to immediately upload'),
+ '$notify' => ['notify', t('Show in your contacts shared folder'), 0, '', [t('No'), t('Yes')]]
));
}
diff --git a/Zotlabs/Storage/File.php b/Zotlabs/Storage/File.php
index 7a102134f..332bf6896 100644
--- a/Zotlabs/Storage/File.php
+++ b/Zotlabs/Storage/File.php
@@ -254,7 +254,7 @@ class File extends DAV\Node implements DAV\IFile {
// @todo this should be a global definition
$unsafe_types = array('text/html', 'text/css', 'application/javascript');
- if (in_array($r[0]['filetype'], $unsafe_types)) {
+ if (in_array($r[0]['filetype'], $unsafe_types) && (! channel_codeallowed($this->data['uid']))) {
header('Content-disposition: attachment; filename="' . $r[0]['filename'] . '"');
header('Content-type: text/plain');
}
@@ -300,7 +300,7 @@ class File extends DAV\Node implements DAV\IFile {
public function getContentType() {
// @todo this should be a global definition.
$unsafe_types = array('text/html', 'text/css', 'application/javascript');
- if (in_array($this->data['filetype'], $unsafe_types)) {
+ if (in_array($this->data['filetype'], $unsafe_types) && (! channel_codeallowed($this->data['uid']))) {
return 'text/plain';
}
return $this->data['filetype'];
diff --git a/Zotlabs/Web/CheckJS.php b/Zotlabs/Web/CheckJS.php
index 109790fa5..8179ceb15 100644
--- a/Zotlabs/Web/CheckJS.php
+++ b/Zotlabs/Web/CheckJS.php
@@ -21,9 +21,9 @@ class CheckJS {
$page = urlencode(\App::$query_string);
if($test) {
- self::$jsdisabled = 1;
+ $this->jsdisabled = 1;
if(array_key_exists('jsdisabled',$_COOKIE))
- self::$jsdisabled = $_COOKIE['jsdisabled'];
+ $this->jsdisabled = $_COOKIE['jsdisabled'];
if(! array_key_exists('jsdisabled',$_COOKIE)) {
\App::$page['htmlhead'] .= "\r\n" . '<script>document.cookie="jsdisabled=0; path=/"; var jsMatch = /\&jsdisabled=0/; if (!jsMatch.exec(location.href)) { location.href = "' . z_root() . '/nojs/0?f=&redir=' . $page . '" ; }</script>' . "\r\n";
@@ -41,7 +41,7 @@ class CheckJS {
}
function disabled() {
- return self::$jsdisabled;
+ return $this->jsdisabled;
}
diff --git a/Zotlabs/Web/HTTPHeaders.php b/Zotlabs/Web/HTTPHeaders.php
index 1e4c1bf84..4be51a8f3 100644
--- a/Zotlabs/Web/HTTPHeaders.php
+++ b/Zotlabs/Web/HTTPHeaders.php
@@ -40,6 +40,20 @@ class HTTPHeaders {
function fetch() {
return $this->parsed;
}
+
+ function fetcharr() {
+ $ret = [];
+ if($this->parsed) {
+ foreach($this->parsed as $x) {
+ foreach($x as $y => $z) {
+ $ret[$y] = $z;
+ }
+ }
+ }
+ return $ret;
+ }
+
+
}
diff --git a/Zotlabs/Web/HTTPSig.php b/Zotlabs/Web/HTTPSig.php
new file mode 100644
index 000000000..1c66b8cf4
--- /dev/null
+++ b/Zotlabs/Web/HTTPSig.php
@@ -0,0 +1,313 @@
+<?php
+
+namespace Zotlabs\Web;
+
+/**
+ * Implements HTTP Signatures per draft-cavage-http-signatures-07
+ */
+
+
+class HTTPSig {
+
+ // See RFC5843
+
+ static function generate_digest($body,$set = true) {
+ $digest = base64_encode(hash('sha256',$body,true));
+
+ if($set) {
+ header('Digest: SHA-256=' . $digest);
+ }
+ return $digest;
+ }
+
+ // See draft-cavage-http-signatures-08
+
+ static function verify($data,$key = '') {
+
+ $body = $data;
+ $headers = null;
+ $spoofable = false;
+
+ $result = [
+ 'signer' => '',
+ 'header_signed' => false,
+ 'header_valid' => false,
+ 'content_signed' => false,
+ 'content_valid' => false
+ ];
+
+ // decide if $data arrived via controller submission or curl
+ if(is_array($data) && $data['header']) {
+ if(! $data['success'])
+ return $result;
+ $h = new \Zotlabs\Web\HTTPHeaders($data['header']);
+ $headers = $h->fetcharr();
+ $body = $data['body'];
+ }
+
+ else {
+ $headers = [];
+ $headers['(request-target)'] =
+ strtolower($_SERVER['REQUEST_METHOD']) . ' ' .
+ $_SERVER['REQUEST_URI'];
+ foreach($_SERVER as $k => $v) {
+ if(strpos($k,'HTTP_') === 0) {
+ $field = str_replace('_','-',strtolower(substr($k,5)));
+ $headers[$field] = $v;
+ }
+ }
+ }
+
+ $sig_block = null;
+
+ if(array_key_exists('signature',$headers)) {
+ $sig_block = self::parse_sigheader($headers['signature']);
+ }
+ elseif(array_key_exists('authorization',$headers)) {
+ $sig_block = self::parse_sigheader($headers['authorization']);
+ }
+
+ if(! $sig_block) {
+ logger('no signature provided.');
+ return $result;
+ }
+
+ // Warning: This log statement includes binary data
+ // logger('sig_block: ' . print_r($sig_block,true), LOGGER_DATA);
+
+ $result['header_signed'] = true;
+
+ $signed_headers = $sig_block['headers'];
+ if(! $signed_headers)
+ $signed_headers = [ 'date' ];
+
+ $signed_data = '';
+ foreach($signed_headers as $h) {
+ if(array_key_exists($h,$headers)) {
+ $signed_data .= $h . ': ' . $headers[$h] . "\n";
+ }
+ if(strpos($h,'.')) {
+ $spoofable = true;
+ }
+ }
+ $signed_data = rtrim($signed_data,"\n");
+
+ $algorithm = null;
+ if($sig_block['algorithm'] === 'rsa-sha256') {
+ $algorithm = 'sha256';
+ }
+ if($sig_block['algorithm'] === 'rsa-sha512') {
+ $algorithm = 'sha512';
+ }
+
+ if($key && function_exists($key)) {
+ $result['signer'] = $sig_block['keyId'];
+ $key = $key($sig_block['keyId']);
+ }
+
+ if(! $key) {
+ $result['signer'] = $sig_block['keyId'];
+ $key = self::get_activitypub_key($sig_block['keyId']);
+ }
+
+ if(! $key)
+ return $result;
+
+ $x = rsa_verify($signed_data,$sig_block['signature'],$key,$algorithm);
+
+ logger('verified: ' . $x, LOGGER_DEBUG);
+
+ if($x === false)
+ return $result;
+
+ if(! $spoofable)
+ $result['header_valid'] = true;
+
+ if(in_array('digest',$signed_headers)) {
+ $result['content_signed'] = true;
+ $digest = explode('=', $headers['digest']);
+ if($digest[0] === 'SHA-256')
+ $hashalg = 'sha256';
+ if($digest[0] === 'SHA-512')
+ $hashalg = 'sha512';
+
+ // The explode operation will have stripped the '=' padding, so compare against unpadded base64
+ if(rtrim(base64_encode(hash($hashalg,$body,true)),'=') === $digest[1]) {
+ $result['content_valid'] = true;
+ }
+ }
+
+ logger('Content_Valid: ' . $result['content_valid']);
+
+ return $result;
+
+ }
+
+ function get_activitypub_key($id) {
+
+ if(strpos($id,'acct:') === 0) {
+ $x = q("select xchan_pubkey from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_addr = '%s' limit 1",
+ dbesc(str_replace('acct:','',$id))
+ );
+ }
+ else {
+ $x = q("select xchan_pubkey from xchan where xchan_hash = '%s' and xchan_network = 'activitypub' ",
+ dbesc($id)
+ );
+ }
+
+ if($x && $x[0]['xchan_pubkey']) {
+ return ($x[0]['xchan_pubkey']);
+ }
+ $r = as_fetch($id);
+
+ if($r) {
+ $j = json_decode($r,true);
+
+ if($j['id'] !== $id)
+ return false;
+ if(array_key_exists('publicKey',$j) && array_key_exists('publicKeyPem',$j['publicKey'])) {
+ return($j['publicKey']['publicKeyPem']);
+ }
+ }
+ return false;
+ }
+
+
+
+
+ static function create_sig($request,$head,$prvkey,$keyid = 'Key',$send_headers = false,$auth = false,$alg = 'sha256',
+ $crypt_key = null, $crypt_algo = 'aes256ctr') {
+
+ $return_headers = [];
+
+ if($alg === 'sha256') {
+ $algorithm = 'rsa-sha256';
+ }
+ if($alg === 'sha512') {
+ $algorithm = 'rsa-sha512';
+ }
+
+ $x = self::sign($request,$head,$prvkey,$alg);
+
+ $headerval = 'keyId="' . $keyid . '",algorithm="' . $algorithm
+ . '",headers="' . $x['headers'] . '",signature="' . $x['signature'] . '"';
+
+ if($crypt_key) {
+ $x = crypto_encapsulate($headerval,$crypt_key,$crypt_alg);
+ $headerval = 'iv="' . $x['iv'] . '",key="' . $x['key'] . '",alg="' . $x['alg'] . '",data="' . $x['data'];
+ }
+
+ if($auth) {
+ $sighead = 'Authorization: Signature ' . $headerval;
+ }
+ else {
+ $sighead = 'Signature: ' . $headerval;
+ }
+
+ if($head) {
+ foreach($head as $k => $v) {
+ if($send_headers) {
+ header($k . ': ' . $v);
+ }
+ else {
+ $return_headers[] = $k . ': ' . $v;
+ }
+ }
+ }
+ if($send_headers) {
+ header($sighead);
+ }
+ else {
+ $return_headers[] = $sighead;
+ }
+ return $return_headers;
+ }
+
+
+
+ static function sign($request,$head,$prvkey,$alg = 'sha256') {
+
+ $ret = [];
+
+ $headers = '';
+ $fields = '';
+ if($request) {
+ $headers = '(request-target)' . ': ' . trim($request) . "\n";
+ $fields = '(request-target)';
+ }
+
+ if(head) {
+ foreach($head as $k => $v) {
+ $headers .= strtolower($k) . ': ' . trim($v) . "\n";
+ if($fields)
+ $fields .= ' ';
+ $fields .= strtolower($k);
+ }
+ // strip the trailing linefeed
+ $headers = rtrim($headers,"\n");
+ }
+
+ $sig = base64_encode(rsa_sign($headers,$prvkey,$alg));
+
+ $ret['headers'] = $fields;
+ $ret['signature'] = $sig;
+
+ return $ret;
+ }
+
+ static function parse_sigheader($header) {
+
+ $ret = [];
+ $matches = [];
+
+ // if the header is encrypted, decrypt with (default) site private key and continue
+
+ if(preg_match('/iv="(.*?)"/ism',$header,$matches))
+ $header = self::decrypt_sigheader($header);
+
+ if(preg_match('/keyId="(.*?)"/ism',$header,$matches))
+ $ret['keyId'] = $matches[1];
+ if(preg_match('/algorithm="(.*?)"/ism',$header,$matches))
+ $ret['algorithm'] = $matches[1];
+ if(preg_match('/headers="(.*?)"/ism',$header,$matches))
+ $ret['headers'] = explode(' ', $matches[1]);
+ if(preg_match('/signature="(.*?)"/ism',$header,$matches))
+ $ret['signature'] = base64_decode(preg_replace('/\s+/','',$matches[1]));
+
+ if(($ret['signature']) && ($ret['algorithm']) && (! $ret['headers']))
+ $ret['headers'] = [ 'date' ];
+
+ return $ret;
+ }
+
+
+ static function decrypt_sigheader($header,$prvkey = null) {
+
+ $iv = $key = $alg = $data = null;
+
+ if(! $prvkey) {
+ $prvkey = get_config('system','prvkey');
+ }
+
+ $matches = [];
+
+ if(preg_match('/iv="(.*?)"/ism',$header,$matches))
+ $iv = $matches[1];
+ if(preg_match('/key="(.*?)"/ism',$header,$matches))
+ $key = $matches[1];
+ if(preg_match('/alg="(.*?)"/ism',$header,$matches))
+ $alg = $matches[1];
+ if(preg_match('/data="(.*?)"/ism',$header,$matches))
+ $data = $matches[1];
+
+ if($iv && $key && $alg && $data) {
+ return crypto_unencapsulate([ 'iv' => $iv, 'key' => $key, 'alg' => $alg, 'data' => $data ] , $prvkey);
+ }
+ return '';
+
+ }
+
+}
+
+
diff --git a/Zotlabs/Web/Router.php b/Zotlabs/Web/Router.php
index 3190369c8..9486130cb 100644
--- a/Zotlabs/Web/Router.php
+++ b/Zotlabs/Web/Router.php
@@ -119,6 +119,18 @@ class Router {
if(! (\App::$module_loaded)) {
+ // undo the setting of a letsencrypt acme-challenge rewrite rule
+ // which blocks access to our .well-known routes.
+ // Also provide a config setting for sites that have a legitimate need
+ // for a custom .htaccess in the .well-known directory; but they should
+ // make the file read-only so letsencrypt doesn't modify it
+
+ if(strpos($_SERVER['REQUEST_URI'],'/.well-known/') === 0) {
+ if(file_exists('.well-known/.htaccess') && get_config('system','fix_apache_acme',true)) {
+ rename('.well-known/.htaccess','.well-known/.htaccess.old');
+ }
+ }
+
$x = [
'module' => $module,
'installed' => \App::$module_loaded,
@@ -166,6 +178,7 @@ class Router {
*/
if(\App::$module_loaded) {
+
\App::$page['page_title'] = \App::$module;
$placeholder = '';
diff --git a/Zotlabs/Web/WebServer.php b/Zotlabs/Web/WebServer.php
index 4e8dc6786..9e6af8c4c 100644
--- a/Zotlabs/Web/WebServer.php
+++ b/Zotlabs/Web/WebServer.php
@@ -58,7 +58,11 @@ class WebServer {
if((x($_GET,'zid')) && (! \App::$install)) {
\App::$query_string = strip_zids(\App::$query_string);
if(! local_channel()) {
- $_SESSION['my_address'] = $_GET['zid'];
+ if ($_SESSION['my_address']!=$_GET['zid'])
+ {
+ $_SESSION['my_address'] = $_GET['zid'];
+ $_SESSION['authenticated'] = 0;
+ }
zid_init();
}
}
@@ -70,6 +74,12 @@ class WebServer {
}
}
+ if((x($_REQUEST,'owt')) && (! \App::$install)) {
+ $token = $_REQUEST['owt'];
+ \App::$query_string = strip_query_param(\App::$query_string,'owt');
+ owt_init($token);
+ }
+
if((x($_SESSION, 'authenticated')) || (x($_POST, 'auth-params')) || (\App::$module === 'login'))
require('include/auth.php');
@@ -97,10 +107,38 @@ class WebServer {
check_config();
}
- nav_set_selected('nothing');
+ //nav_set_selected('nothing');
$Router = new Router($a);
+ /* Initialise the Link: response header if this is a channel page.
+ * This cannot be done inside the channel module because some protocol
+ * addons over-ride the module functions and these links are common
+ * to all protocol drivers; thus doing it here avoids duplication.
+ */
+
+ if (( \App::$module === 'channel' ) && argc() > 1) {
+ \App::$channel_links = [
+ [
+ 'rel' => 'lrdd',
+ 'type' => 'application/xrd+xml',
+ 'url' => z_root() . '/xrd?f=&uri=acct%3A' . argv(1) . '%40' . \App::get_hostname()
+ ],
+ [
+ 'rel' => 'jrd',
+ 'type' => 'application/jrd+json',
+ 'url' => z_root() . '/.well-known/webfinger?f=&resource=acct%3A' . argv(1) . '%40' . \App::get_hostname()
+ ],
+ ];
+ $x = [ 'channel_address' => argv(1), 'channel_links' => \App::$channel_links ];
+ call_hooks('channel_links', $x );
+ \App::$channel_links = $x['channel_links'];
+ header('Link: ' . \App::get_channel_links());
+ }
+
+
+
+
/* initialise content region */
if(! x(\App::$page, 'content'))
@@ -137,4 +175,4 @@ class WebServer {
killme();
}
-} \ No newline at end of file
+}
diff --git a/Zotlabs/Widget/Categories.php b/Zotlabs/Widget/Categories.php
index d1dcfda93..305869706 100644
--- a/Zotlabs/Widget/Categories.php
+++ b/Zotlabs/Widget/Categories.php
@@ -8,16 +8,25 @@ class Categories {
function widget($arr) {
+ $cards = ((array_key_exists('cards',$arr) && $arr['cards']) ? true : false);
+
+ if(($cards) && (! feature_enabled(\App::$profile['profile_uid'],'cards')))
+ return '';
+
if((! \App::$profile['profile_uid'])
- || (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),'view_stream'))) {
+ || (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),(($cards) ? 'view_pages' : 'view_stream')))) {
return '';
}
$cat = ((x($_REQUEST,'cat')) ? htmlspecialchars($_REQUEST['cat'],ENT_COMPAT,'UTF-8') : '');
- $srchurl = \App::$query_string;
+ $srchurl = (($cards) ? \App::$argv[0] . '/' . \App::$argv[1] : \App::$query_string);
$srchurl = rtrim(preg_replace('/cat\=[^\&].*?(\&|$)/is','',$srchurl),'&');
$srchurl = str_replace(array('?f=','&f='),array('',''),$srchurl);
- return categories_widget($srchurl, $cat);
+ if($cards)
+ return cardcategories_widget($srchurl, $cat);
+ else
+ return categories_widget($srchurl, $cat);
+
}
}
diff --git a/Zotlabs/Widget/Common_friends.php b/Zotlabs/Widget/Common_friends.php
new file mode 100644
index 000000000..a67b9312c
--- /dev/null
+++ b/Zotlabs/Widget/Common_friends.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+require_once('include/contact_widgets.php');
+
+class Common_friends {
+
+ function widget($arr) {
+
+ if((! \App::$profile['profile_uid'])
+ || (! perm_is_allowed(\App::$profile['profile_uid'],get_observer_hash(),'view_contacts'))) {
+ return '';
+ }
+
+ return common_friends_visitor_widget(\App::$profile['profile_uid']);
+
+ }
+}
diff --git a/Zotlabs/Widget/Helpindex.php b/Zotlabs/Widget/Helpindex.php
index f23e73e75..6c8748194 100644
--- a/Zotlabs/Widget/Helpindex.php
+++ b/Zotlabs/Widget/Helpindex.php
@@ -9,14 +9,23 @@ class Helpindex {
$o .= '<div class="widget">';
$level_0 = get_help_content('sitetoc');
- if(! $level_0)
- $level_0 = get_help_content('toc');
+ if(! $level_0) {
+ $path = 'toc';
+ $x = determine_help_language();
+ $lang = $x['language'];
+ if($lang !== 'en') {
+ $path = $lang . '/toc';
+ }
+ $level_0 = get_help_content($path);
+ }
$level_0 = preg_replace('/\<ul(.*?)\>/','<ul class="nav nav-pills flex-column">',$level_0);
$levels = array();
+ // TODO: Implement support for translations in hierarchical table of content files
+ /*
if(argc() > 2) {
$path = '';
for($x = 1; $x < argc(); $x ++) {
@@ -28,6 +37,7 @@ class Helpindex {
$levels[] = preg_replace('/\<ul(.*?)\>/','<ul class="nav nav-pills flex-column">',$y);
}
}
+ */
if($level_0)
$o .= $level_0;
diff --git a/Zotlabs/Widget/Notifications.php b/Zotlabs/Widget/Notifications.php
new file mode 100644
index 000000000..a857f1ad9
--- /dev/null
+++ b/Zotlabs/Widget/Notifications.php
@@ -0,0 +1,150 @@
+<?php
+
+namespace Zotlabs\Widget;
+
+class Notifications {
+
+ function widget($arr) {
+
+ $channel = \App::get_channel();
+
+ if(local_channel()) {
+ $notifications[] = [
+ 'type' => 'network',
+ 'icon' => 'th',
+ 'severity' => 'secondary',
+ 'label' => t('New Network Activity'),
+ 'title' => t('New Network Activity Notifications'),
+ 'viewall' => [
+ 'url' => 'network',
+ 'label' => t('View your network activity')
+ ],
+ 'markall' => [
+ 'url' => '#',
+ 'label' => t('Mark all notifications read')
+ ]
+ ];
+
+ $notifications[] = [
+ 'type' => 'home',
+ 'icon' => 'home',
+ 'severity' => 'danger',
+ 'label' => t('New Home Activity'),
+ 'title' => t('New Home Activity Notifications'),
+ 'viewall' => [
+ 'url' => 'channel/' . $channel['channel_address'],
+ 'label' => t('View your home activity')
+ ],
+ 'markall' => [
+ 'url' => '#',
+ 'label' => t('Mark all notifications seen')
+ ]
+ ];
+
+ $notifications[] = [
+ 'type' => 'mail',
+ 'icon' => 'envelope',
+ 'severity' => 'danger',
+ 'label' => t('New Mails'),
+ 'title' => t('New Mails Notifications'),
+ 'viewall' => [
+ 'url' => 'mail/combined',
+ 'label' => t('View your private mails')
+ ],
+ 'markall' => [
+ 'url' => '#',
+ 'label' => t('Mark all messages seen')
+ ]
+ ];
+
+ $notifications[] = [
+ 'type' => 'all_events',
+ 'icon' => 'calendar',
+ 'severity' => 'secondary',
+ 'label' => t('New Events'),
+ 'title' => t('New Events Notifications'),
+ 'viewall' => [
+ 'url' => 'mail/combined',
+ 'label' => t('View events')
+ ],
+ 'markall' => [
+ 'url' => '#',
+ 'label' => t('Mark all events seen')
+ ]
+ ];
+
+ $notifications[] = [
+ 'type' => 'intros',
+ 'icon' => 'users',
+ 'severity' => 'danger',
+ 'label' => t('New Connections'),
+ 'title' => t('New Connections Notifications'),
+ 'viewall' => [
+ 'url' => 'connections',
+ 'label' => t('View all connections')
+ ]
+ ];
+
+ $notifications[] = [
+ 'type' => 'files',
+ 'icon' => 'folder',
+ 'severity' => 'danger',
+ 'label' => t('New Files'),
+ 'title' => t('New Files Notifications'),
+ ];
+
+ $notifications[] = [
+ 'type' => 'notify',
+ 'icon' => 'exclamation',
+ 'severity' => 'danger',
+ 'label' => t('Notices'),
+ 'title' => t('Notices'),
+ 'viewall' => [
+ 'url' => 'notifications/system',
+ 'label' => t('View all notices')
+ ],
+ 'markall' => [
+ 'url' => '#',
+ 'label' => t('Mark all notices seen')
+ ]
+ ];
+ }
+
+ if(local_channel() && is_site_admin()) {
+ $notifications[] = [
+ 'type' => 'register',
+ 'icon' => 'user-o',
+ 'severity' => 'danger',
+ 'label' => t('New Registrations'),
+ 'title' => t('New Registrations Notifications'),
+ ];
+ }
+
+ if(get_config('system', 'disable_discover_tab') != 1) {
+ $notifications[] = [
+ 'type' => 'pubs',
+ 'icon' => 'globe',
+ 'severity' => 'secondary',
+ 'label' => t('Public Stream'),
+ 'title' => t('Public Stream Notifications'),
+ 'viewall' => [
+ 'url' => 'pubstream',
+ 'label' => t('View the public stream')
+ ],
+ 'markall' => [
+ 'url' => '#',
+ 'label' => t('Mark all notifications seen')
+ ]
+ ];
+ }
+
+ $o = replace_macros(get_markup_template('notifications_widget.tpl'), array(
+ '$notifications' => $notifications,
+ '$loading' => t('Loading...')
+ ));
+
+ return $o;
+
+ }
+}
+
diff --git a/Zotlabs/Widget/Wiki_pages.php b/Zotlabs/Widget/Wiki_pages.php
index a07c348ff..6e3a22551 100644
--- a/Zotlabs/Widget/Wiki_pages.php
+++ b/Zotlabs/Widget/Wiki_pages.php
@@ -37,6 +37,7 @@ class Wiki_pages {
if (!$wikiname) {
$wikiname = '';
}
+ $typelock = $w['typelock'];
}
$can_create = perm_is_allowed(\App::$profile['uid'],get_observer_hash(),'write_wiki');
@@ -52,8 +53,14 @@ class Wiki_pages {
'$canadd' => $can_create,
'$candel' => $can_delete,
'$addnew' => t('Add new page'),
+ '$typelock' => $typelock,
+ '$lockedtype' => $w['mimeType'],
+ '$mimetype' => mimetype_select(0,$w['mimeType'],
+ [ 'text/markdown' => t('Markdown'), 'text/bbcode' => t('BBcode'), 'text/plain' => t('Text') ]),
'$pageName' => array('pageName', t('Page name')),
- '$refresh' => $arr['refresh']
+ '$refresh' => $arr['refresh'],
+ '$options' => t('Options'),
+ '$submit' => t('Submit')
));
}
}
diff --git a/Zotlabs/Zot/Auth.php b/Zotlabs/Zot/Auth.php
index 92b0fff78..8d198f506 100644
--- a/Zotlabs/Zot/Auth.php
+++ b/Zotlabs/Zot/Auth.php
@@ -43,6 +43,12 @@ class Auth {
$this->Finalise();
}
+ if(strpbrk($this->sec,'.:')) {
+ logger('illegal security context');
+ $this->Debug('illegal security context.');
+ $this->Finalise();
+ }
+
$x = $this->GetHublocs($this->address);
if($x) {
@@ -109,6 +115,14 @@ class Auth {
$this->remote_hub = $hubloc['hubloc_url'];
$this->dnt = 0;
+ if(! $this->sec) {
+ logger('missing security context.');
+ if($this->test)
+ $this->Debug('missing security context.');
+ return false;
+ }
+
+
// check credentials and access
// If they are already authenticated and haven't changed credentials,
diff --git a/Zotlabs/Zot/Finger.php b/Zotlabs/Zot/Finger.php
index 9871b5bbd..348171bdc 100644
--- a/Zotlabs/Zot/Finger.php
+++ b/Zotlabs/Zot/Finger.php
@@ -22,6 +22,7 @@ class Finger {
*
* @return zotinfo array (with 'success' => true) or array('success' => false);
*/
+
static public function run($webbie, $channel = null, $autofallback = true) {
$ret = array('success' => false);
@@ -84,18 +85,27 @@ class Finger {
'token' => self::$token
);
- $result = z_post_url($url . $rhs,$postvars);
+ $headers = [];
+ $headers['X-Zot-Channel'] = $channel['channel_address'] . '@' . \App::get_hostname();
+ $headers['X-Zot-Nonce'] = random_string();
+ $xhead = \Zotlabs\Web\HTTPSig::create_sig('',$headers,$channel['channel_prvkey'],
+ 'acct:' . $channel['channel_address'] . '@' . \App::get_hostname(),false);
+
+ $retries = 0;
+
+ $result = z_post_url($url . $rhs,$postvars,$retries, [ 'headers' => $xhead ]);
if ((! $result['success']) && ($autofallback)) {
if ($https) {
logger('zot_finger: https failed. falling back to http');
- $result = z_post_url('http://' . $host . $rhs,$postvars);
+ $result = z_post_url('http://' . $host . $rhs,$postvars, $retries, [ 'headers' => $xhead ]);
}
}
- } else {
+ }
+ else {
$rhs .= '?f=&address=' . urlencode($address) . '&token=' . self::$token;
- $result = z_fetch_url($url . $rhs);
+ $result = z_fetch_url($url . $rhs);
if((! $result['success']) && ($autofallback)) {
if($https) {
logger('zot_finger: https failed. falling back to http');
@@ -111,7 +121,10 @@ class Finger {
}
$x = json_decode($result['body'], true);
- if($x) {
+
+ $verify = \Zotlabs\Web\HTTPSig::verify($result,(($x) ? $x['key'] : ''));
+
+ if($x && (! $verify['header_valid'])) {
$signed_token = ((is_array($x) && array_key_exists('signed_token', $x)) ? $x['signed_token'] : null);
if($signed_token) {
$valid = rsa_verify('token.' . self::$token, base64url_decode($signed_token), $x['key']);
diff --git a/Zotlabs/Zot/IHandler.php b/Zotlabs/Zot/IHandler.php
index eeca1555c..dd82f5be6 100644
--- a/Zotlabs/Zot/IHandler.php
+++ b/Zotlabs/Zot/IHandler.php
@@ -12,6 +12,8 @@ interface IHandler {
function Request($data);
+ function Rekey($sender,$data);
+
function AuthCheck($data,$encrypted);
function Purge($sender,$recipients);
diff --git a/Zotlabs/Zot/Receiver.php b/Zotlabs/Zot/Receiver.php
index 0050a2559..c521c9d64 100644
--- a/Zotlabs/Zot/Receiver.php
+++ b/Zotlabs/Zot/Receiver.php
@@ -120,6 +120,10 @@ class Receiver {
$this->handler->Notify($this->data);
break;
+ case 'rekey':
+ $this->handler->Rekey($this->sender, $this->data);
+ break;
+
default:
$this->response['message'] = 'Not implemented';
json_return_and_die($this->response);
diff --git a/Zotlabs/Zot/Verify.php b/Zotlabs/Zot/Verify.php
index 06bd3188c..1d9e6de3f 100644
--- a/Zotlabs/Zot/Verify.php
+++ b/Zotlabs/Zot/Verify.php
@@ -31,6 +31,22 @@ class Verify {
return false;
}
+
+ function get_meta($type,$channel_id,$token) {
+ $r = q("select id, meta from verify where vtype = '%s' and channel = %d and token = '%s' limit 1",
+ dbesc($type),
+ intval($channel_id),
+ dbesc($token)
+ );
+ if($r) {
+ q("delete from verify where id = %d",
+ intval($r[0]['id'])
+ );
+ return $r[0]['meta'];
+ }
+ return false;
+ }
+
function purge($type,$interval) {
q("delete from verify where vtype = '%s' and created < %s - INTERVAL %s",
dbesc($type),
diff --git a/Zotlabs/Zot/ZotHandler.php b/Zotlabs/Zot/ZotHandler.php
index aab336545..ab8815b3d 100644
--- a/Zotlabs/Zot/ZotHandler.php
+++ b/Zotlabs/Zot/ZotHandler.php
@@ -20,6 +20,10 @@ class ZotHandler implements IHandler {
zot_reply_message_request($data);
}
+ function Rekey($sender,$data) {
+ zot_rekey_request($sender,$data);
+ }
+
function AuthCheck($data,$encrypted) {
zot_reply_auth_check($data,$encrypted);
}