Merge remote-tracking branch 'mike/dev' into dev

This commit is contained in:
OJ Random 2022-12-22 22:35:54 +01:00
commit d07bb40a0d
147 changed files with 3189 additions and 2707 deletions

View file

@ -4,16 +4,16 @@ namespace Code\Daemon;
use Code\Extend\Hook; use Code\Extend\Hook;
class Addon class Addon implements DaemonInterface
{ {
/** /**
* @param $argc * @param int $argc
* @param $argv * @param array $argv
* @return void * @return void
* @noinspection PhpUnusedParameterInspection * @noinspection PhpUnusedParameterInspection
*/ */
public function run($argc, $argv): void public function run(int $argc, array $argv): void
{ {
Hook::call('daemon_addon', $argv); Hook::call('daemon_addon', $argv);
} }

View file

@ -7,9 +7,9 @@ use Code\Lib\Resizer;
require_once('include/photos.php'); require_once('include/photos.php');
class CacheThumb class CacheThumb implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
if ($argc != 2) { if ($argc != 2) {
return; return;

View file

@ -2,17 +2,16 @@
namespace Code\Daemon; namespace Code\Daemon;
class Cache_embeds class Cache_embeds implements DaemonInterface
{ {
/** /**
* @param $argc * @param int $argc
* @param $argv * @param array $argv
* @return void * @return void
*/ */
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
if (! $argc == 2) { if (! $argc == 2) {
return; return;
} }

View file

@ -4,15 +4,15 @@ namespace Code\Daemon;
use Code\Lib\Img_cache; use Code\Lib\Img_cache;
class Cache_image class Cache_image implements DaemonInterface
{ {
/** /**
* @param $argc * @param int $argc
* @param $argv * @param array $argv
* @return void * @return void
*/ */
public function run($argc, $argv): void public function run(int $argc, array $argv): void
{ {
cli_startup(); cli_startup();
logger('caching: ' . $argv[1] . ' to ' . $argv[2]); logger('caching: ' . $argv[1] . ' to ' . $argv[2]);

View file

@ -4,11 +4,11 @@ namespace Code\Daemon;
use Code\Lib\Channel; use Code\Lib\Channel;
class Channel_purge class Channel_purge implements DaemonInterface
{ {
/** @noinspection PhpUnusedParameterInspection */ /** @noinspection PhpUnusedParameterInspection */
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
cli_startup(); cli_startup();

View file

@ -7,10 +7,10 @@ namespace Code\Daemon;
require_once('include/hubloc.php'); require_once('include/hubloc.php');
class Checksites class Checksites implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
logger('checksites: start'); logger('checksites: start');

View file

@ -10,11 +10,11 @@ require_once('include/cli_startup.php');
require_once('include/attach.php'); require_once('include/attach.php');
require_once('include/import.php'); require_once('include/import.php');
class Content_importer class Content_importer implements DaemonInterface
{ {
/** @noinspection PhpUnusedParameterInspection */ /** @noinspection PhpUnusedParameterInspection */
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
cli_startup(); cli_startup();

View file

@ -7,10 +7,15 @@ use Code\Lib\ActivityStreams;
use Code\Lib\ASCollection; use Code\Lib\ASCollection;
use Code\Lib\Channel; use Code\Lib\Channel;
class Convo class Convo implements DaemonInterface
{ {
public function run($argc, $argv) /**
* @param int $argc
* @param array $argv
* @return void
*/
public function run(int $argc, array $argv): void
{ {
logger('convo invoked: ' . print_r($argv, true)); logger('convo invoked: ' . print_r($argv, true));
@ -54,7 +59,9 @@ class Convo
$AS = new ActivityStreams($message, null, true); $AS = new ActivityStreams($message, null, true);
if ($AS->is_valid() && is_array($AS->obj)) { if ($AS->is_valid() && is_array($AS->obj)) {
$item = Activity::decode_note($AS, true); $item = Activity::decode_note($AS, true);
Activity::store($channel, $contact['abook_xchan'], $AS, $item, true, true); if ($item) {
Activity::store($channel, $contact['abook_xchan'], $AS, $item, true, true);
}
} }
} }
} }

View file

@ -6,13 +6,12 @@ namespace Code\Daemon;
use Code\Lib\Config; use Code\Lib\Config;
use Code\Lib\Libsync; use Code\Lib\Libsync;
use Code\Lib\Channel;
use Code\Lib\Addon; use Code\Lib\Addon;
class Cron class Cron implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
$maxsysload = intval(get_config('system', 'maxloadavg')); $maxsysload = intval(get_config('system', 'maxloadavg'));

View file

@ -3,14 +3,13 @@
namespace Code\Daemon; namespace Code\Daemon;
use Code\Lib\ServiceClass; use Code\Lib\ServiceClass;
use Code\Lib\Libzotdir;
use Code\Lib\Libzot; use Code\Lib\Libzot;
use Code\Extend\Hook; use Code\Extend\Hook;
class Cron_daily class Cron_daily implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
logger('cron_daily: start'); logger('cron_daily: start');

View file

@ -5,10 +5,10 @@ namespace Code\Daemon;
use Code\Lib\Channel; use Code\Lib\Channel;
use Code\Extend\Hook; use Code\Extend\Hook;
class Cron_weekly class Cron_weekly implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
/** /**

View file

@ -5,10 +5,10 @@
namespace Code\Daemon; namespace Code\Daemon;
use Code\Extend\Hook; use Code\Extend\Hook;
class Cronhooks class Cronhooks implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
logger('cronhooks: start'); logger('cronhooks: start');
@ -16,7 +16,5 @@ class Cronhooks
$d = datetime_convert(); $d = datetime_convert();
Hook::call('cron', $d); Hook::call('cron', $d);
return;
} }
} }

View file

@ -0,0 +1,8 @@
<?php
namespace Code\Daemon;
interface DaemonInterface
{
public function run(int $argc, array $argv): void;
}

View file

@ -6,10 +6,10 @@ namespace Code\Daemon;
use Code\Lib\Queue; use Code\Lib\Queue;
class Deliver class Deliver implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
if ($argc < 2) { if ($argc < 2) {
return; return;

View file

@ -4,10 +4,10 @@ namespace Code\Daemon;
use Code\Extend\Hook; use Code\Extend\Hook;
class Deliver_hooks class Deliver_hooks implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
if ($argc < 2) { if ($argc < 2) {

View file

@ -6,10 +6,10 @@ namespace Code\Daemon;
* Daemon to remove 'item' resources in the background from a removed connection * Daemon to remove 'item' resources in the background from a removed connection
*/ */
class Delxitems class Delxitems implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
cli_startup(); cli_startup();
@ -19,7 +19,5 @@ class Delxitems
} }
remove_abook_items($argv[1], $argv[2]); remove_abook_items($argv[1], $argv[2]);
return;
} }
} }

View file

@ -2,15 +2,13 @@
namespace Code\Daemon; namespace Code\Daemon;
use Code\Lib\Libzot;
use Code\Lib\Libzotdir; use Code\Lib\Libzotdir;
use Code\Lib\Queue;
use Code\Lib\Channel; use Code\Lib\Channel;
class Directory class Directory implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
if ($argc < 2) { if ($argc < 2) {

View file

@ -5,10 +5,10 @@ namespace Code\Daemon;
use Code\Lib\ServiceClass; use Code\Lib\ServiceClass;
use Code\Lib\Channel; use Code\Lib\Channel;
class Expire class Expire implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
cli_startup(); cli_startup();

View file

@ -10,10 +10,10 @@ require_once('include/cli_startup.php');
require_once('include/attach.php'); require_once('include/attach.php');
require_once('include/import.php'); require_once('include/import.php');
class File_importer class File_importer implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
cli_startup(); cli_startup();

View file

@ -10,10 +10,10 @@ use Code\Lib\Zotfinger;
// performs zot_finger on $argv[1], which is a hex_encoded webbie/reddress // performs zot_finger on $argv[1], which is a hex_encoded webbie/reddress
class Gprobe class Gprobe implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
if ($argc != 2) { if ($argc != 2) {

View file

@ -2,10 +2,10 @@
namespace Code\Daemon; namespace Code\Daemon;
class Importdoc class Importdoc implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
require_once('include/help.php'); require_once('include/help.php');
@ -30,7 +30,7 @@ class Importdoc
self::update_docs_dir("$fi/*"); self::update_docs_dir("$fi/*");
} else { } else {
// don't update media content // don't update media content
if (strpos(z_mime_content_type($fi), 'text') === 0) { if (str_starts_with(z_mime_content_type($fi), 'text')) {
store_doc_file($fi); store_doc_file($fi);
} }
} }

View file

@ -7,10 +7,10 @@ namespace Code\Daemon;
use Code\Lib\Libsync; use Code\Lib\Libsync;
use Code\Lib\Channel; use Code\Lib\Channel;
class Importfile class Importfile implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
logger('Importfile: ' . print_r($argv, true)); logger('Importfile: ' . print_r($argv, true));
@ -50,9 +50,7 @@ class Importfile
$sync = attach_export_data($channel, $hash); $sync = attach_export_data($channel, $hash);
if ($sync) { if ($sync) {
Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
} }
return;
} }
} }

View file

@ -2,6 +2,8 @@
namespace Code\Daemon; namespace Code\Daemon;
use Code\Lib\Config;
use Code\Lib\IConfig;
use Code\Lib\Libzot; use Code\Lib\Libzot;
use Code\Lib\Queue; use Code\Lib\Queue;
use Code\Lib\Activity; use Code\Lib\Activity;
@ -74,7 +76,7 @@ require_once('include/bbcode.php');
* keychange channel_id * keychange channel_id
* *
*/ */
class Notifier class Notifier implements DaemonInterface
{ {
public static $deliveries = []; public static $deliveries = [];
@ -86,7 +88,7 @@ class Notifier
public static $channel = null; public static $channel = null;
public static $private = false; public static $private = false;
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
if ($argc < 3) { if ($argc < 3) {
@ -346,11 +348,7 @@ class Notifier
if ($m && (! intval($target_item['item_deleted']))) { if ($m && (! intval($target_item['item_deleted']))) {
self::$encoded_item = json_decode($m, true); self::$encoded_item = json_decode($m, true);
} else { } else {
self::$encoded_item = array_merge(['@context' => [ self::$encoded_item = array_merge(Activity::ap_context(), Activity::encode_activity($target_item, true));
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
Activity::ap_schema()
]], Activity::encode_activity($target_item, true));
self::$encoded_item['signature'] = LDSignatures::sign(self::$encoded_item, self::$channel); self::$encoded_item['signature'] = LDSignatures::sign(self::$encoded_item, self::$channel);
} }
@ -387,44 +385,53 @@ class Notifier
if (($relay_to_owner || $uplink) && ($cmd !== 'relay')) { if (($relay_to_owner || $uplink) && ($cmd !== 'relay')) {
logger('followup relay (upstream delivery)', LOGGER_DEBUG); logger('followup relay (upstream delivery)', LOGGER_DEBUG);
$sendto = ($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan'];
self::$recipients = [ $sendto ]; $comment_recipient = IConfig::Get($target_item['id'], 'system', 'comment_recipient');
// over-ride upstream recipients if 'replyTo' was set in the parent. if ($comment_recipient) {
if ($parent_item['replyto'] && (! $uplink)) { $sendto = $comment_recipient;
logger('replyto: over-riding owner ' . $sendto, LOGGER_DEBUG); self::$recipients = [$comment_recipient];
// unserialise is a no-op if presented with data that wasn't serialised. self::$private = false;
$ptr = unserialise($parent_item['replyto']); }
if (is_string($ptr)) { else {
if (ActivityStreams::is_url($sendto)) { $sendto = ($uplink) ? $parent_item['source_xchan'] : $parent_item['owner_xchan'];
$sendto = $ptr; self::$recipients = [$sendto];
self::$recipients = [ $sendto ]; // over-ride upstream recipients if 'replyTo' was set in the parent.
} if ($parent_item['replyto'] && (!$uplink)) {
} elseif (is_array($ptr)) { logger('replyto: over-riding owner ' . $sendto, LOGGER_DEBUG);
$sendto = []; // unserialise is a no-op if presented with data that wasn't serialised.
foreach ($ptr as $rto) { $ptr = unserialise($parent_item['replyto']);
if (is_string($rto)) { if (is_string($ptr)) {
$sendto[] = $rto; if (ActivityStreams::is_url($sendto)) {
} elseif (is_array($rto) && isset($rto['id'])) { $sendto = $ptr;
$sendto[] = $rto['id']; self::$recipients = [$sendto];
} }
} elseif (is_array($ptr)) {
$sendto = [];
foreach ($ptr as $rto) {
if (is_string($rto)) {
$sendto[] = $rto;
} elseif (is_array($rto) && isset($rto['id'])) {
$sendto[] = $rto['id'];
}
}
self::$recipients = $sendto;
} }
self::$recipients = $sendto;
} }
} }
logger('replyto: upstream recipients ' . print_r($sendto, true), LOGGER_DEBUG); logger('replyto: upstream recipients ' . print_r($sendto, true), LOGGER_DEBUG);
self::$private = true; self::$private = true;
$upstream = true; $upstream = true;
self::$packet_type = 'response'; self::$packet_type = 'response';
$is_moderated = their_perms_contains($parent_item['uid'], $sendto, 'moderated'); $is_moderated = their_perms_contains($parent_item['uid'], (is_array($sendto) ? $sendto[0] : $sendto), 'moderated');
if ($relay_to_owner && $thread_is_public && (! $is_moderated) && (! $question) && (! Channel::is_group($parent_item['uid']))) { $allowed_comment = $target_item['approved'] || !Config::Get('system', 'use_fep5624');
if ($relay_to_owner && $thread_is_public && $allowed_comment && (! $is_moderated) && (! $question) && (! Channel::is_group($parent_item['uid']))) {
if (get_pconfig($target_item['uid'], 'system', 'hyperdrive', true)) { if (get_pconfig($target_item['uid'], 'system', 'hyperdrive', true)) {
Run::Summon([ 'Notifier' , 'hyper', $item_id ]); Run::Summon([ 'Notifier' , 'hyper', $item_id ]);
} }
} }
} else { }
else {
if ($cmd === 'relay') { if ($cmd === 'relay') {
logger('owner relay (downstream delivery)'); logger('owner relay (downstream delivery)');
} else { } else {
@ -451,7 +458,8 @@ class Notifier
} }
} }
if ($thread_is_public && $cmd === 'hyper') {
if ($thread_is_public && $target_item['approved'] && $cmd === 'hyper') {
self::$recipients = []; self::$recipients = [];
$r = q( $r = q(
"select abook_xchan, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and abook_pending = 0 and abook_archived = 0 and not abook_xchan in ( '%s', '%s', '%s' ) ", "select abook_xchan, xchan_network from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_self = 0 and abook_pending = 0 and abook_archived = 0 and not abook_xchan in ( '%s', '%s', '%s' ) ",
@ -465,8 +473,8 @@ class Notifier
self::$recipients[] = $rv['abook_xchan']; self::$recipients[] = $rv['abook_xchan'];
} }
} }
self::$private = false; }
} else { else {
self::$private = false; self::$private = false;
self::$recipients = collect_recipients($parent_item, self::$private); self::$recipients = collect_recipients($parent_item, self::$private);
} }

View file

@ -11,10 +11,10 @@ use Code\Lib\ASCollection;
use Code\Lib\Socgraph; use Code\Lib\Socgraph;
use Code\Lib\PConfig; use Code\Lib\PConfig;
class Onepoll class Onepoll implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
logger('onepoll: start'); logger('onepoll: start');

View file

@ -7,10 +7,10 @@ namespace Code\Daemon;
use Code\Lib\ServiceClass; use Code\Lib\ServiceClass;
use Code\Lib\Addon; use Code\Lib\Addon;
class Poller class Poller implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
$maxsysload = intval(get_config('system', 'maxloadavg')); $maxsysload = intval(get_config('system', 'maxloadavg'));

View file

@ -6,10 +6,10 @@ namespace Code\Daemon;
use Code\Lib as Zlib; use Code\Lib as Zlib;
class Queue class Queue implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
$queue_id = ($argc > 1) ? $argv[1] : ''; $queue_id = ($argc > 1) ? $argv[1] : '';

View file

@ -6,10 +6,10 @@ namespace Code\Daemon;
use Code\Extend\Hook; use Code\Extend\Hook;
class Thumbnail class Thumbnail implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
if (! ($argc == 2)) { if (! ($argc == 2)) {

View file

@ -4,10 +4,10 @@
namespace Code\Daemon; namespace Code\Daemon;
class Xchan_photo class Xchan_photo implements DaemonInterface
{ {
public function run($argc, $argv) public function run(int $argc, array $argv): void
{ {
if ($argc != 3) { if ($argc != 3) {

View file

@ -145,6 +145,7 @@ class OAuth2Storage extends Pdo
public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null, $client_name = null): bool public function setClientDetails($client_id, $client_secret = null, $redirect_uri = null, $grant_types = null, $scope = null, $user_id = null, $client_name = null): bool
{ {
// if it exists, update it. // if it exists, update it.
if ($this->getClientDetails($client_id)) { if ($this->getClientDetails($client_id)) {
$stmt = $this->db->prepare(sprintf('UPDATE %s SET client_secret=:client_secret, redirect_uri=:redirect_uri, grant_types=:grant_types, scope=:scope, user_id=:user_id, client_name=:client_name where client_id=:client_id', $this->config['client_table'])); $stmt = $this->db->prepare(sprintf('UPDATE %s SET client_secret=:client_secret, redirect_uri=:redirect_uri, grant_types=:grant_types, scope=:scope, user_id=:user_id, client_name=:client_name where client_id=:client_id', $this->config['client_table']));

View file

@ -44,7 +44,7 @@ class ASCollection
} }
if (!in_array($data['type'], ['Collection', 'OrderedCollection'])) { if (!in_array($data['type'], ['Collection', 'OrderedCollection'])) {
return false; return;
} }
if ($this->direction) { if ($this->direction) {

View file

@ -229,11 +229,11 @@ class AccessList
} }
public static function members($uid, $gid, $total = false, $start = 0, $records = 0): mixed public static function members($uid, $gid, $total = false, $start = 0, $records = 0, $sqlExtra = ''): mixed
{ {
$ret = []; $ret = [];
$pager_sql = ''; $pager_sql = '';
$sql_extra = ''; $sql_extra = $sqlExtra;
if ($records) { if ($records) {
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($records), intval($start)); $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($records), intval($start));
@ -263,7 +263,8 @@ class AccessList
$r = q( $r = q(
"SELECT * FROM abook left join xchan on xchan_hash = abook_xchan "SELECT * FROM abook left join xchan on xchan_hash = abook_xchan
WHERE abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 $sql_extra ORDER BY xchan_name ASC $pager_sql", WHERE abook_channel = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0
and abook_pending = 0 $sql_extra ORDER BY xchan_name ASC $pager_sql",
intval($uid) intval($uid)
); );
if ($r) { if ($r) {
@ -280,7 +281,7 @@ class AccessList
"SELECT count(xchan) as total FROM pgrp_member "SELECT count(xchan) as total FROM pgrp_member
LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan
WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0
and abook_blocked = 0 and abook_pending = 0", and abook_blocked = 0 and abook_pending = 0 $sqlExtra",
intval($gid), intval($gid),
intval($uid), intval($uid),
intval($uid) intval($uid)
@ -293,7 +294,7 @@ class AccessList
$r = q( $r = q(
"SELECT * FROM pgrp_member "SELECT * FROM pgrp_member
LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan LEFT JOIN abook ON abook_xchan = pgrp_member.xchan left join xchan on xchan_hash = abook_xchan
WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 ORDER BY xchan_name ASC $pager_sql", WHERE gid = %d AND abook_channel = %d and pgrp_member.uid = %d and xchan_deleted = 0 and abook_self = 0 and abook_blocked = 0 and abook_pending = 0 $sqlExtra ORDER BY xchan_name ASC $pager_sql",
intval($gid), intval($gid),
intval($uid), intval($uid),
intval($uid) intval($uid)

View file

@ -264,9 +264,7 @@ class Account {
public static function verify_email_address($arr) public static function verify_email_address($arr)
{ {
if (array_key_exists('resend', $arr)) { if (array_key_exists('resend', $arr)) {
$email = $arr['email'];
$a = q( $a = q(
"select * from account where account_email = '%s' limit 1", "select * from account where account_email = '%s' limit 1",
dbesc($arr['email']) dbesc($arr['email'])

File diff suppressed because it is too large Load diff

View file

@ -55,11 +55,7 @@ class ActivityPub
'cc' => [] 'cc' => []
]; ];
$msg = array_merge(['@context' => [ $msg = array_merge(Activity::ap_context(), $ti);
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
Activity::ap_schema()
]], $ti);
$msg['signature'] = LDSignatures::sign($msg, $arr['channel']); $msg['signature'] = LDSignatures::sign($msg, $arr['channel']);
@ -107,11 +103,7 @@ class ActivityPub
// } // }
// } // }
$msg = array_merge(['@context' => [ $msg = array_merge(Activity::ap_context(), $ti);
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
Activity::ap_schema()
]], $ti);
$msg['signature'] = LDSignatures::sign($msg, $arr['channel']); $msg['signature'] = LDSignatures::sign($msg, $arr['channel']);
@ -266,11 +258,7 @@ class ActivityPub
$orig_follow_type = get_abconfig($x['sender']['channel_id'], $x['recipient']['xchan_hash'], 'activitypub', 'their_follow_type'); $orig_follow_type = get_abconfig($x['sender']['channel_id'], $x['recipient']['xchan_hash'], 'activitypub', 'their_follow_type');
$msg = array_merge( $msg = array_merge(
['@context' => [ Activity::ap_context(),
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
Activity::ap_schema()
]],
[ [
'id' => z_root() . '/follow/' . $x['recipient']['abook_id'] . (($orig_follow) ? '/' . md5($orig_follow) : EMPTY_STR), 'id' => z_root() . '/follow/' . $x['recipient']['abook_id'] . (($orig_follow) ? '/' . md5($orig_follow) : EMPTY_STR),
'type' => (($orig_follow_type) ?: 'Follow'), 'type' => (($orig_follow_type) ?: 'Follow'),
@ -341,11 +329,7 @@ class ActivityPub
} }
$msg = array_merge( $msg = array_merge(
['@context' => [ Activity::ap_context(),
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
Activity::ap_schema()
]],
[ [
'id' => z_root() . '/follow/' . $x['recipient']['abook_id'] . '/' . md5($accept), 'id' => z_root() . '/follow/' . $x['recipient']['abook_id'] . '/' . md5($accept),
'type' => 'Accept', 'type' => 'Accept',
@ -410,11 +394,7 @@ class ActivityPub
// was never approved // was never approved
$msg = array_merge( $msg = array_merge(
['@context' => [ Activity::ap_context(),
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
Activity::ap_schema()
]],
[ [
'id' => z_root() . '/follow/' . $recip[0]['abook_id'] . '/' . md5($orig_activity) . '?operation=reject', 'id' => z_root() . '/follow/' . $recip[0]['abook_id'] . '/' . md5($orig_activity) . '?operation=reject',
'type' => 'Reject', 'type' => 'Reject',
@ -434,11 +414,7 @@ class ActivityPub
// send an 'unfollow' // send an 'unfollow'
$msg = array_merge( $msg = array_merge(
['@context' => [ Activity::ap_context(),
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
Activity::ap_schema()
]],
[ [
'id' => z_root() . '/follow/' . $recip[0]['abook_id'] . (($orig_activity) ? '/' . md5($orig_activity) : EMPTY_STR) . '?operation=unfollow', 'id' => z_root() . '/follow/' . $recip[0]['abook_id'] . (($orig_activity) ? '/' . md5($orig_activity) : EMPTY_STR) . '?operation=unfollow',
'type' => 'Undo', 'type' => 'Undo',

View file

@ -280,7 +280,7 @@ class Channel
public static function create($arr) public static function create($arr)
{ {
$ret = array('success' => false); $ret = ['success' => false];
if (! $arr['account_id']) { if (! $arr['account_id']) {
$ret['message'] = t('No account identifier'); $ret['message'] = t('No account identifier');
@ -313,7 +313,7 @@ class Channel
return $ret; return $ret;
} }
if (check_webbie(array($nick)) !== $nick) { if (check_webbie([$nick]) !== $nick) {
$ret['message'] = t('Nickname has unsupported characters or is already being used on this site.'); $ret['message'] = t('Nickname has unsupported characters or is already being used on this site.');
return $ret; return $ret;
} }
@ -352,7 +352,7 @@ class Channel
} }
$xchannel_type = XCHAN_TYPE_PERSON ; $xchannel_type = XCHAN_TYPE_PERSON ;
if (strpos($arr['permissions_role'], 'forum') !== false || strpos($arr['permissions_role'], 'group') !== false) { if (str_contains($arr['permissions_role'], 'forum') || str_contains($arr['permissions_role'], 'group')) {
$xchannel_type = XCHAN_TYPE_GROUP ; $xchannel_type = XCHAN_TYPE_GROUP ;
} }
if ($system) { if ($system) {
@ -589,7 +589,7 @@ class Channel
$accts = get_config('system', 'auto_follow'); $accts = get_config('system', 'auto_follow');
if (($accts) && (! $total_identities)) { if (($accts) && (! $total_identities)) {
if (! is_array($accts)) { if (! is_array($accts)) {
$accts = array($accts); $accts = [$accts];
} }
foreach ($accts as $acct) { foreach ($accts as $acct) {
@ -636,7 +636,7 @@ class Channel
if ($f['success']) { if ($f['success']) {
$clone = []; $clone = [];
foreach ($f['abook'] as $k => $v) { foreach ($f['abook'] as $k => $v) {
if (strpos($k, 'abook_') === 0) { if (str_starts_with($k, 'abook_')) {
$clone[$k] = $v; $clone[$k] = $v;
} }
} }
@ -659,7 +659,7 @@ class Channel
public static function change_channel_keys($channel) public static function change_channel_keys($channel)
{ {
$ret = array('success' => false); $ret = ['success' => false];
$stored = []; $stored = [];
@ -756,7 +756,7 @@ class Channel
); );
} }
xchan_change_key($oldxchan, $newxchan, $stored); xchan_change_key($oldxchan, $newxchan);
Run::Summon([ 'Notifier', 'keychange', $channel['channel_id'] ]); Run::Summon([ 'Notifier', 'keychange', $channel['channel_id'] ]);
@ -767,7 +767,7 @@ class Channel
public static function change_address($channel, $new_address) public static function change_address($channel, $new_address)
{ {
$ret = array('success' => false); $ret = ['success' => false];
$old_address = $channel['channel_address']; $old_address = $channel['channel_address'];
@ -776,7 +776,7 @@ class Channel
return $ret; return $ret;
} }
if (check_webbie(array($new_address)) !== $new_address) { if (check_webbie([$new_address]) !== $new_address) {
$ret['message'] = t('Nickname has unsupported characters or is already being used on this site.'); $ret['message'] = t('Nickname has unsupported characters or is already being used on this site.');
return $ret; return $ret;
} }
@ -1423,7 +1423,7 @@ class Channel
if (! local_channel()) { if (! local_channel()) {
$r = q( $r = q(
"select * from hubloc where hubloc_addr = '%s' and hubloc_deleted = 0 order by hubloc_connected desc limit 1", "select * from hubloc where hubloc_addr = '%s' and hubloc_deleted = 0 order by hubloc_id desc limit 1",
dbesc($tmp_str) dbesc($tmp_str)
); );
if (! $r) { if (! $r) {
@ -1436,9 +1436,9 @@ class Channel
logger('Not authenticated. Invoking reverse magic-auth for ' . $tmp_str); logger('Not authenticated. Invoking reverse magic-auth for ' . $tmp_str);
// try to avoid recursion - but send them home to do a proper magic auth // try to avoid recursion - but send them home to do a proper magic auth
$query = App::$query_string; $query = App::$query_string;
$query = str_replace(array('?zid=','&zid='), array('?rzid=','&rzid='), $query); $query = str_replace(['?zid=','&zid='], ['?rzid=','&rzid='], $query);
$dest = '/' . $query; $dest = '/' . $query;
if ($r && ($r[0]['hubloc_url'] != z_root()) && (! strstr($dest, '/magic')) && (! strstr($dest, '/rmagic'))) { if ($r && ($r[0]['hubloc_url'] != z_root()) && (!str_contains($dest, '/magic')) && (!str_contains($dest, '/rmagic'))) {
goaway($r[0]['hubloc_url'] . '/magic' . '?f=&rev=1&owa=1&bdest=' . bin2hex(z_root() . $dest)); goaway($r[0]['hubloc_url'] . '/magic' . '?f=&rev=1&owa=1&bdest=' . bin2hex(z_root() . $dest));
} else { } else {
logger(sprintf('No hubloc found for \'%s\'.', $tmp_str)); logger(sprintf('No hubloc found for \'%s\'.', $tmp_str));
@ -1575,7 +1575,7 @@ class Channel
public static function get_online_status($nick) public static function get_online_status($nick)
{ {
$ret = array('result' => false); $ret = ['result' => false];
$r = q( $r = q(
"select channel_id, channel_hash from channel where channel_address = '%s' limit 1", "select channel_id, channel_hash from channel where channel_address = '%s' limit 1",
@ -1610,7 +1610,7 @@ class Channel
$result = false; $result = false;
$r = q( $r = q(
"select * from hubloc where hubloc_addr = '%s' and hubloc_deleted = 0 limit 1", "select * from hubloc where hubloc_addr = '%s' and hubloc_deleted = 0 order by hubloc_id desc limit 1",
dbesc($webbie) dbesc($webbie)
); );
if (! $r) { if (! $r) {
@ -1643,10 +1643,10 @@ class Channel
intval(get_account_id()) intval(get_account_id())
); );
if ($r && count($r) > 1) { if ($r && count($r) > 1) {
$o = replace_macros(Theme::get_template('channel_id_select.tpl'), array( $o = replace_macros(Theme::get_template('channel_id_select.tpl'), [
'$channels' => $r, '$channels' => $r,
'$selected' => local_channel() '$selected' => local_channel()
)); ]);
return $o; return $o;
} }
@ -1679,7 +1679,7 @@ class Channel
$profile_fields_basic = (($filter == 0) ? get_config('system', 'profile_fields_basic') : null); $profile_fields_basic = (($filter == 0) ? get_config('system', 'profile_fields_basic') : null);
if (! $profile_fields_basic) { if (! $profile_fields_basic) {
$profile_fields_basic = array('fullname','pdesc','chandesc','basic_gender','pronouns','dob','dob_tz','region','country_name','marital','sexual','homepage','hometown','keywords','about','contact'); $profile_fields_basic = ['fullname','pdesc','chandesc','basic_gender','pronouns','dob','dob_tz','region','country_name','marital','sexual','homepage','hometown','keywords','about','contact'];
} }
$x = []; $x = [];
@ -1698,7 +1698,7 @@ class Channel
$basic = self::get_profile_fields_basic($filter); $basic = self::get_profile_fields_basic($filter);
$profile_fields_advanced = (($filter == 0) ? get_config('system', 'profile_fields_advanced') : null); $profile_fields_advanced = (($filter == 0) ? get_config('system', 'profile_fields_advanced') : null);
if (! $profile_fields_advanced) { if (! $profile_fields_advanced) {
$profile_fields_advanced = array('comms', 'address','locality','postal_code','advanced_gender', 'partner','howlong','politic','religion','likes','dislikes','interest','channels','music','book','film','tv','romance','employment','education'); $profile_fields_advanced = ['comms', 'address','locality','postal_code','advanced_gender', 'partner','howlong','politic','religion','likes','dislikes','interest','channels','music','book','film','tv','romance','employment','education'];
} }
$x = []; $x = [];
if ($basic) { if ($basic) {
@ -1780,7 +1780,7 @@ class Channel
); );
if ($r) { if ($r) {
if ($send) { if ($send) {
Libsync::build_sync_packet($channel_id, array('profile' => $r)); Libsync::build_sync_packet($channel_id, ['profile' => $r]);
} else { } else {
return $r; return $r;
} }
@ -1830,7 +1830,7 @@ class Channel
$arr['nickname'] = $arr['nickname'] . mt_rand(1000, 9999); $arr['nickname'] = $arr['nickname'] . mt_rand(1000, 9999);
} }
$arr['nickname'] = check_webbie(array($arr['nickname'], $arr['nickname'] . mt_rand(1000, 9999))); $arr['nickname'] = check_webbie([$arr['nickname'], $arr['nickname'] . mt_rand(1000, 9999)]);
return self::create($arr); return self::create($arr);
} }
@ -1861,13 +1861,13 @@ class Channel
break; break;
case 'array': case 'array':
default: default:
$output = array( $output = [
'width' => $r[0]['width'], 'width' => $r[0]['width'],
'height' => $r[0]['height'], 'height' => $r[0]['height'],
'type' => $r[0]['mimetype'], 'type' => $r[0]['mimetype'],
'updated' => $r[0]['edited'], 'updated' => $r[0]['edited'],
'url' => $url 'url' => $url
); ];
break; break;
} }
@ -1901,19 +1901,19 @@ class Channel
$cover_width = 425; $cover_width = 425;
$size = 'hz_small'; $size = 'hz_small';
$cover_size = PHOTO_RES_COVER_425; $cover_size = PHOTO_RES_COVER_425;
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m'] . '?rev=' . strtotime($channel['xchan_photo_date'])); $pphoto = ['mimetype' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m'] . '?rev=' . strtotime($channel['xchan_photo_date'])];
} elseif ($maxwidth <= 900) { } elseif ($maxwidth <= 900) {
$width = 900; $width = 900;
$cover_width = 850; $cover_width = 850;
$size = 'hz_medium'; $size = 'hz_medium';
$cover_size = PHOTO_RES_COVER_850; $cover_size = PHOTO_RES_COVER_850;
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l'] . '?rev=' . strtotime($channel['xchan_photo_date'])); $pphoto = ['mimetype' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l'] . '?rev=' . strtotime($channel['xchan_photo_date'])];
} elseif ($maxwidth <= 1200) { } elseif ($maxwidth <= 1200) {
$width = 1200; $width = 1200;
$cover_width = 1200; $cover_width = 1200;
$size = 'hz_large'; $size = 'hz_large';
$cover_size = PHOTO_RES_COVER_1200; $cover_size = PHOTO_RES_COVER_1200;
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l'] . '?rev=' . strtotime($channel['xchan_photo_date'])); $pphoto = ['mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l'] . '?rev=' . strtotime($channel['xchan_photo_date'])];
} }
// $scale = (float) $maxwidth / $width; // $scale = (float) $maxwidth / $width;
@ -1922,7 +1922,7 @@ class Channel
$translate = 0; $translate = 0;
$channel['channel_addr'] = self::get_webfinger($channel); $channel['channel_addr'] = self::get_webfinger($channel);
$zcard = array('chan' => $channel); $zcard = ['chan' => $channel];
$r = q( $r = q(
"select height, width, resource_id, imgscale, mimetype from photo where uid = %d and imgscale = %d and photo_usage = %d", "select height, width, resource_id, imgscale, mimetype from photo where uid = %d and imgscale = %d and photo_usage = %d",
@ -1938,7 +1938,7 @@ class Channel
$cover = [ 'href' => z_root() . '/' . self::get_default_cover_photo($cover_width) ]; $cover = [ 'href' => z_root() . '/' . self::get_default_cover_photo($cover_width) ];
} }
$o = replace_macros(Theme::get_template('zcard.tpl'), array( $o = replace_macros(Theme::get_template('zcard.tpl'), [
'$maxwidth' => $maxwidth, '$maxwidth' => $maxwidth,
'$scale' => $scale, '$scale' => $scale,
'$translate' => $translate, '$translate' => $translate,
@ -1946,7 +1946,7 @@ class Channel
'$cover' => $cover, '$cover' => $cover,
'$pphoto' => $pphoto, '$pphoto' => $pphoto,
'$zcard' => $zcard '$zcard' => $zcard
)); ]);
return $o; return $o;
} }
@ -1978,23 +1978,23 @@ class Channel
$cover_width = 425; $cover_width = 425;
$size = 'hz_small'; $size = 'hz_small';
$cover_size = PHOTO_RES_COVER_425; $cover_size = PHOTO_RES_COVER_425;
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m']); $pphoto = ['mimetype' => $channel['xchan_photo_mimetype'], 'width' => 80 , 'height' => 80, 'href' => $channel['xchan_photo_m']];
} elseif ($maxwidth <= 900) { } elseif ($maxwidth <= 900) {
$width = 900; $width = 900;
$cover_width = 850; $cover_width = 850;
$size = 'hz_medium'; $size = 'hz_medium';
$cover_size = PHOTO_RES_COVER_850; $cover_size = PHOTO_RES_COVER_850;
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l']); $pphoto = ['mimetype' => $channel['xchan_photo_mimetype'], 'width' => 160 , 'height' => 160, 'href' => $channel['xchan_photo_l']];
} elseif ($maxwidth <= 1200) { } elseif ($maxwidth <= 1200) {
$width = 1200; $width = 1200;
$cover_width = 1200; $cover_width = 1200;
$size = 'hz_large'; $size = 'hz_large';
$cover_size = PHOTO_RES_COVER_1200; $cover_size = PHOTO_RES_COVER_1200;
$pphoto = array('mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l']); $pphoto = ['mimetype' => $channel['xchan_photo_mimetype'], 'width' => 300 , 'height' => 300, 'href' => $channel['xchan_photo_l']];
} }
$channel['channel_addr'] = self::get_webfinger($channel); $channel['channel_addr'] = self::get_webfinger($channel);
$zcard = array('chan' => $channel); $zcard = ['chan' => $channel];
$r = q( $r = q(
"select height, width, resource_id, imgscale, mimetype from photo where uid = %d and imgscale = %d and photo_usage = %d", "select height, width, resource_id, imgscale, mimetype from photo where uid = %d and imgscale = %d and photo_usage = %d",
@ -2158,11 +2158,11 @@ class Channel
*/ */
public static function remote_login() public static function remote_login()
{ {
$o = replace_macros(Theme::get_template('remote_login.tpl'), array( $o = replace_macros(Theme::get_template('remote_login.tpl'), [
'$title' => t('Remote Authentication'), '$title' => t('Remote Authentication'),
'$desc' => t('Enter your channel address (e.g. channel@example.com)'), '$desc' => t('Enter your channel address (e.g. channel@example.com)'),
'$submit' => t('Authenticate') '$submit' => t('Authenticate')
)); ]);
return $o; return $o;
} }

View file

@ -0,0 +1,301 @@
<?php
namespace Code\Lib;
use Code\Daemon\Run;
class CommentApproval
{
protected $channel;
protected $item;
public function __construct($channel, $item)
{
$this->channel = $channel;
$this->item = $item;
}
public function Accept()
{
$obj = $this->item['obj'];
if (! is_array($obj)) {
$obj = json_decode($obj, true);
}
// Have I approved this already?
$approvals = q("select * from item where verb = 'Accept' and obj = '%s' and uid = %d",
dbesc('"' . $obj['id'] . '"'),
dbesc($this->channel['channel_id'])
);
if ($approvals) {
return;
}
$parent = $this->get_parent();
$activity = post_activity_item(
[
'verb' => 'Accept',
'obj_type' => $obj['type'],
'obj' => $obj['id'],
'item_wall' => 1,
'allow_cid' => '',
'owner_xchan' => $this->channel['xchan_hash'],
'author_xchan' => $this->channel['xchan_hash'],
'parent_mid' => $parent,
'thr_parent' => $parent,
'uid' => $this->channel['channel_id'],
'title' => 'comment accepted'
],
deliver: false,
channel: $this->channel,
observer: $this->channel
);
if ($activity['item_id']) {
IConfig::Set($activity['item_id'], 'system', 'comment_recipient', $this->item['author_xchan']);
}
q("UPDATE item SET approved = '%s' WHERE id = %d",
dbesc(str_replace('/item/','/activity/', $activity['activity']['mid'])),
intval($activity['item_id'])
);
Run::Summon(['Notifier', 'comment_approval', $activity['item_id']]);
}
public function Reject()
{
$obj = $this->item['obj'];
if (! is_array($obj)) {
$obj = json_decode($obj, true);
}
// Have I rejected this already?
$rejections = q("select * from item where verb = 'Reject' and obj = '%s' and uid = %d",
dbesc('"' . $obj['id'] . '"'),
dbesc($this->channel['channel_id'])
);
if ($rejections) {
return;
}
$parent = $this->get_parent();
$activity = post_activity_item(
[
'verb' => 'Reject',
'obj_type' => $obj['type'],
'obj' => $obj['id'],
'item_wall' => 1,
'allow_cid' => '',
'owner_xchan' => $this->channel['xchan_hash'],
'author_xchan' => $this->channel['xchan_hash'],
'parent_mid' => $parent,
'thr_parent' => $parent,
'uid' => $this->channel['channel_id'],
'title' => 'comment rejected'
],
deliver: false,
channel: $this->channel,
observer: $this->channel
);
if ($activity['item_id']) {
IConfig::Set($activity['item_id'], 'system', 'comment_recipient', $this->item['author_xchan']);
}
q("UPDATE item SET approved = '' WHERE id = %d",
intval($activity['item_id'])
);
Run::Summon(['Notifier', 'comment_approval', $activity['item_id']]);
}
/**
* To be considered valid, the Accept activity referenced in approval MUST
* satisfy the following properties:
*
* its actor property is the authority
* its authenticity can be asserted
* its object property is the reply under consideration
* its inReplyTo property matches that of the reply under consideration
*
* In addition, if the reply is considered valid, but has no valid approval
* despite the object it is in reply to having a canReply property, the recipient MAY hide
* the reply from certain views.
*/
public static function verify($item, $channel, $approvalActivity = null)
{
if(!$approvalActivity) {
$approvalActivity = Activity::fetch($item['approved'], $channel, true);
}
if (! $approvalActivity) {
logger('no approval activity');
return false;
}
$parent_item = q("select * from item where mid = '%s'", $item['parent_mid']);
if (!$parent_item) {
logger('no parent item');
return false;
}
if ($approvalActivity instanceof ActivityStreams) {
$act = $approvalActivity;
}
else {
$act = new ActivityStreams($approvalActivity);
}
if (! $act->is_valid()) {
logger('invalid parse');
return false;
}
if (!$act->obj) {
logger('no object');
return false;
}
if ($act->type !== 'Accept') {
logger('not an accept');
return false;
}
if (!isset($act->actor)) {
logger('no actor');
return false;
}
$sender = Activity::find_best_identity($act->actor['id']);
if (!$sender || $sender !== $parent_item[0]['owner_xchan']) {
logger('no identity');
return false;
}
$comment = is_string($act->obj) ? $act->obj : $act->obj['id'];
if ($comment !== $item['mid']) {
logger('incorrect mid');
return false;
}
if(!in_array($act->parent_id, [$item['thr_parent'], $item['parent_mid']])) {
logger('wrong provenance');
logger('act: ' . $act->parent_id);
logger('item: ' . print_r($item,true));
return false;
}
logger('comment verified', LOGGER_DEBUG);
return true;
}
public static function verifyReject($item, $channel, $approvalActivity = null)
{
if(!$approvalActivity) {
$approvalActivity = Activity::fetch($item['approved'], $channel, true);
}
$parent_item = q("select * from item where mid = '%s'", $item['parent_mid']);
if (! $approvalActivity) {
return false;
}
if (!$parent_item) {
return false;
}
if ($approvalActivity instanceof ActivityStreams) {
$act = $approvalActivity;
}
else {
$act = new ActivityStreams($approvalActivity);
}
if (! $act->is_valid()) {
return false;
}
if (!$act->obj) {
return false;
}
if ($act->type !== 'Reject') {
return false;
}
if (!isset($act->actor)) {
return false;
}
$sender = Activity::find_best_identity($act->actor['id']);
if (!$sender || $sender !== $parent_item['owner_xchan']) {
return false;
}
$comment = is_string($act->obj) ? $act->obj : $act->obj['id'];
if ($comment !== $item['mid']) {
return false;
}
if(!in_array($act->parent_id, [$item['thr_parent'], $item['parent_mid']])) {
return false;
}
logger('comment verified', LOGGER_DEBUG);
return true;
}
public static function doVerify($arr, $channel, $act)
{
logger('verifying comment accept/reject', LOGGER_DEBUG);
$i = q("select * from item where mid = '%s' and uid = %d",
dbesc(is_array($arr['obj']) ? $arr['obj']['id'] : $arr['obj']),
intval($channel['channel_id'])
);
if ($i) {
if ($arr['verb'] === 'Accept' && !$i[0]['approved']) {
$valid = self::verify($i[0], $channel, $act);
if ($valid) {
self::storeApprove($arr, $channel, $arr['mid']);
Run::Summon(['Notifier', 'activity', $i[0]['id']]);
}
}
elseif ($i[0]['approved']) {
$valid = self::verifyReject($i[0], $channel, $act);
if ($valid) {
self::storeApprove($arr, $channel, '');
Run::Summon(['Notifier', 'activity', $i[0]['id']]);
}
}
return true;
}
return false;
}
public static function storeApprove($arr, $channel, $value)
{
q("update item set approved = '%s' where mid = '%s' and uid = %d",
dbesc($value),
dbesc(is_array($arr['obj']) ? $arr['obj']['id'] : $arr['obj']),
intval($channel['channel_id'])
);
$saved = q("select * from item where mid = '%s' and uid = %d",
dbesc(is_array($arr['obj']) ? $arr['obj']['id'] : $arr['obj']),
intval($channel['channel_id'])
);
if ($saved) {
// we will need to remove the object and provide an author array
// in order to re-generate the object JSON with the added approval
xchan_query($saved);
$saved[0]['obj'] = '';
q("update item set obj = '%s' where mid = '%s' and uid = '%s'",
dbesc(json_encode(Activity::encode_item($saved[0], true), JSON_UNESCAPED_SLASHES)),
dbesc(is_array($arr['obj']) ? $arr['obj']['id'] : $arr['obj']),
intval($channel['channel_id'])
);
}
$r = q(
"select * from item where mid = '%s' and uid = %d",
dbesc(is_array($arr['obj']) ? $arr['obj']['id'] : $arr['obj']),
intval($channel['channel_id'])
);
if ($r) {
xchan_query($r);
$sync_item = fetch_post_tags($r);
Libsync::build_sync_packet($channel['channel_id'], ['item' => [encode_item($sync_item[0], true)]]);
}
}
protected function get_parent()
{
$result = q("select parent_mid from item where mid = '%s'",
dbesc($this->item['parent_mid'])
);
return $result ? $result[0]['parent_mid'] : '';
}
}

View file

@ -103,6 +103,10 @@ class Enotify
$additional_mail_header = ""; $additional_mail_header = "";
if (array_key_exists('item', $params)) { if (array_key_exists('item', $params)) {
if (in_array($params['item']['verb'], ['Approve', 'Reject'])) {
pop_lang();
return;
}
require_once('include/conversation.php'); require_once('include/conversation.php');
// if it's a normal item... // if it's a normal item...
if (array_key_exists('verb', $params['item'])) { if (array_key_exists('verb', $params['item'])) {

View file

@ -1290,6 +1290,6 @@ class Libsync
); );
} }
xchan_change_key($oldxchan, $newxchan, $arr['keychange']); xchan_change_key($oldxchan, $newxchan);
} }
} }

View file

@ -1304,7 +1304,7 @@ class Libzot
"select hubloc_hash, hubloc_network, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_deleted = 0", "select hubloc_hash, hubloc_network, hubloc_url from hubloc where hubloc_id_url = '%s' and hubloc_deleted = 0",
dbesc($AS->actor['id']) dbesc($AS->actor['id'])
); );
if (! $r) { if (!$r) {
// Author is unknown to this site. Perform channel discovery and try again. // Author is unknown to this site. Perform channel discovery and try again.
$z = discover_resource($AS->actor['id']); $z = discover_resource($AS->actor['id']);
if ($z) { if ($z) {
@ -1382,19 +1382,21 @@ class Libzot
$relay = (($env['type'] === 'response') ? true : false); $relay = (($env['type'] === 'response') ? true : false);
$result = self::process_delivery($env['sender'], $AS, $arr, $deliveries, $relay, false, $message_request); $result = self::process_delivery($env['sender'], $AS, $arr, $deliveries, $relay, false, $message_request);
} elseif ($env['type'] === 'sync') {
$arr = json_decode($data, true);
logger('Channel sync received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG);
logger('Channel sync recipients: ' . print_r($deliveries, true), LOGGER_DATA, LOG_DEBUG);
if ($env['encoding'] === 'red') {
$result = Libsync::process_channel_sync_delivery($env['sender'], $arr, $deliveries);
} else {
logger('unsupported sync packet encoding ignored.');
}
} }
} }
elseif ($env['type'] === 'sync') {
$arr = json_decode($data, true);
logger('Channel sync received: ' . print_r($arr, true), LOGGER_DATA, LOG_DEBUG);
logger('Channel sync recipients: ' . print_r($deliveries, true), LOGGER_DATA, LOG_DEBUG);
if ($env['encoding'] === 'red') {
$result = Libsync::process_channel_sync_delivery($env['sender'], $arr, $deliveries);
} else {
logger('unsupported sync packet encoding ignored.');
}
}
if ($result) { if ($result) {
$return = array_merge($return, $result); $return = array_merge($return, $result);
} }
@ -1597,6 +1599,7 @@ class Libzot
{ {
$result = []; $result = [];
$commentApproval = null;
// logger('msg_arr: ' . print_r($msg_arr,true),LOGGER_ALL); // logger('msg_arr: ' . print_r($msg_arr,true),LOGGER_ALL);
@ -1722,13 +1725,33 @@ class Libzot
} }
} }
if (in_array($arr['verb'], ['Accept', 'Reject'])) {
if (CommentApproval::doVerify($arr, $channel, $act)) {
continue;
}
}
// perform pre-storage check to see if it's "likely" that this is a group or collection post // perform pre-storage check to see if it's "likely" that this is a group or collection post
$tag_delivery = tgroup_check($channel['channel_id'], $arr); $tag_delivery = tgroup_check($channel['channel_id'], $arr);
$perm = 'send_stream'; $perm = 'send_stream';
if (($arr['mid'] !== $arr['parent_mid']) && ($relay)) { if ($arr['mid'] !== $arr['parent_mid']) {
$perm = 'post_comments'; if ($arr['approved']) {
$valid = CommentApproval::verify($arr, $channel);
if (!$valid) {
logger('commentApproval failed');
continue;
}
}
if ($relay) {
$perm = 'post_comments';
if (!$arr['approved'] && $arr['author_xchan'] !== $channel['channel_hash']) {
$commentApproval = new CommentApproval($channel, $arr);
}
}
} }
// This is our own post, possibly coming from a channel clone // This is our own post, possibly coming from a channel clone
@ -1814,7 +1837,16 @@ class Libzot
} }
} }
if($arr['mid'] !== $arr['parent_mid'] && !$arr['approved'] && !$arr['item_wall'] && $arr['author_xchan'] !== $d && !$relay) {
$allowed = !Config::Get('system', 'use_fep5624');
}
if (!$allowed) { if (!$allowed) {
if ($arr['mid'] !== $arr['parent_mid']) {
if ($commentApproval) {
$commentApproval->Reject();
}
}
logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}"); logger("permission denied for delivery to channel {$channel['channel_id']} {$channel['channel_address']}");
$DR->update('permission denied'); $DR->update('permission denied');
$result[] = $DR->get(); $result[] = $DR->get();
@ -1827,28 +1859,15 @@ class Libzot
$arr['item_blocked'] = ITEM_MODERATED; $arr['item_blocked'] = ITEM_MODERATED;
} }
// check source route. if ($commentApproval) {
// We are only going to accept comments from this sender if the comment has the same route as the top-level-post, $commentApproval->Accept();
// this is so that permissions mismatches between senders apply to the entire conversation }
// As a side effect we will also do a preliminary check that we have the top-level-post, otherwise
// processing it is pointless.
// The original author won't have a token in their copy of the message
$prnt = ((str_contains($arr['parent_mid'], 'token=')) ? substr($arr['parent_mid'], 0, strpos($arr['parent_mid'], '?')) : '');
$r = q( $r = q(
"select id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1", "select id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['parent_mid']), dbesc($arr['parent_mid']),
intval($channel['channel_id']) intval($channel['channel_id'])
); );
if (!$r) {
$r = q(
"select id, parent_mid, mid, owner_xchan, item_private, obj_type from item where mid = '%s' and uid = %d limit 1",
dbesc($prnt),
intval($channel['channel_id'])
);
}
if ($r) { if ($r) {
// if this is a multi-threaded conversation, preserve the threading information // if this is a multi-threaded conversation, preserve the threading information
@ -1967,10 +1986,11 @@ class Libzot
continue; continue;
} // Maybe it has been edited? } // Maybe it has been edited?
elseif ($arr['edited'] > $r[0]['edited']) { elseif ($arr['edited'] > $r[0]['edited'] || $arr['approved'] !== $r[0]['approved']) {
$arr['id'] = $r[0]['id']; $arr['id'] = $r[0]['id'];
$arr['uid'] = $channel['channel_id']; $arr['uid'] = $channel['channel_id'];
if (post_is_importable($channel['channel_id'], $arr, $abook)) { if (post_is_importable($channel['channel_id'], $arr, $abook)) {
// ObjCache::Set($arr['mid'], $act->meta['signed_data']);
$item_result = self::update_imported_item($sender, $arr, $r[0], $channel['channel_id'], $tag_delivery); $item_result = self::update_imported_item($sender, $arr, $r[0], $channel['channel_id'], $tag_delivery);
$DR->update('updated'); $DR->update('updated');
$result[] = $DR->get(); $result[] = $DR->get();
@ -2025,7 +2045,7 @@ class Libzot
if (str_contains($arr['body'], "#^[")) { if (str_contains($arr['body'], "#^[")) {
$arr['body'] = str_replace("#^[", "[", $arr['body']); $arr['body'] = str_replace("#^[", "[", $arr['body']);
} }
// ObjCache::Set($arr['mid'], $act->meta['signed_data']);
$item_result = item_store($arr); $item_result = item_store($arr);
if ($item_result['success']) { if ($item_result['success']) {
$item_id = $item_result['item_id']; $item_id = $item_result['item_id'];
@ -2990,7 +3010,7 @@ class Libzot
$ret['follow_url'] = z_root() . '/follow?f=&url=%s'; $ret['follow_url'] = z_root() . '/follow?f=&url=%s';
} }
$permissions = get_all_perms($e['channel_id'], $ztarget_hash, false); $permissions = get_all_perms($e['channel_id'], $ztarget_hash);
if ($ztarget_hash) { if ($ztarget_hash) {
$permissions['connected'] = false; $permissions['connected'] = false;

View file

@ -3,10 +3,7 @@
namespace Code\Lib; namespace Code\Lib;
use App; use App;
use Code\Lib\Libzot;
use Code\Lib\Webfinger;
use Code\Lib\Zotfinger;
use Code\Lib\Channel;
use Code\Extend\Hook; use Code\Extend\Hook;
use Code\Render\Theme; use Code\Render\Theme;
@ -89,12 +86,12 @@ class Libzotdir
$o = replace_macros(Theme::get_template('dir_sort_links.tpl'), [ $o = replace_macros(Theme::get_template('dir_sort_links.tpl'), [
'$header' => t('Directory Options'), '$header' => t('Directory Options'),
'$forumsurl' => $forumsurl, '$forumsurl' => $forumsurl,
'$safemode' => array('safemode', t('Safe Mode'), $safe_mode, '', array(t('No'), t('Yes')), ' onchange=\'window.location.href="' . $forumsurl . '&safe="+(this.checked ? 1 : 0)\''), '$safemode' => ['safemode', t('Safe Mode'), $safe_mode, '', [t('No'), t('Yes')], ' onchange=\'window.location.href="' . $forumsurl . '&safe="+(this.checked ? 1 : 0)\''],
'$pubforums' => array('pubforums', t('Groups Only'), (($pubforums == 1) ? true : false), '', array(t('No'), t('Yes')), ' onchange=\'window.location.href="' . $forumsurl . '&type="+(this.checked ? 1 : 0)\''), '$pubforums' => ['pubforums', t('Groups Only'), (($pubforums == 1) ? true : false), '', [t('No'), t('Yes')], ' onchange=\'window.location.href="' . $forumsurl . '&type="+(this.checked ? 1 : 0)\''],
// '$collections' => array('collections', t('Collections Only'),(($pubforums == 2) ? true : false),'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&type="+(this.checked ? 2 : 0)\''), // '$collections' => array('collections', t('Collections Only'),(($pubforums == 2) ? true : false),'',array(t('No'), t('Yes')),' onchange=\'window.location.href="' . $forumsurl . '&type="+(this.checked ? 2 : 0)\''),
'$hide_local' => $hide_local, '$hide_local' => $hide_local,
'$globaldir' => array('globaldir', t('This Website Only'), 1 - intval($globaldir), '', array(t('No'), t('Yes')), ' onchange=\'window.location.href="' . $forumsurl . '&global="+(this.checked ? 0 : 1)\''), '$globaldir' => ['globaldir', t('This Website Only'), 1 - intval($globaldir), '', [t('No'), t('Yes')], ' onchange=\'window.location.href="' . $forumsurl . '&global="+(this.checked ? 0 : 1)\''],
'$activedir' => array('activedir', t('Recently Updated'), intval($activedir), '', array(t('No'), t('Yes')), ' onchange=\'window.location.href="' . $forumsurl . '&active="+(this.checked ? 1 : 0)\''), '$activedir' => ['activedir', t('Recently Updated'), intval($activedir), '', [t('No'), t('Yes')], ' onchange=\'window.location.href="' . $forumsurl . '&active="+(this.checked ? 1 : 0)\''],
'$covers' => (Config::Get('system','remote_cover_photos')) ? [ 'covers', t('Show cover photos'), intval($covers), t('May slow page loading'), [ t('No'), t('Yes')], ' onchange=\'window.location.href="' . $forumsurl . '&covers="+(this.checked ? 1 : 0)\''] : '', '$covers' => (Config::Get('system','remote_cover_photos')) ? [ 'covers', t('Show cover photos'), intval($covers), t('May slow page loading'), [ t('No'), t('Yes')], ' onchange=\'window.location.href="' . $forumsurl . '&covers="+(this.checked ? 1 : 0)\''] : '',
]); ]);

View file

@ -6,6 +6,9 @@ class ObjCache
{ {
public static function Get($path) public static function Get($path)
{ {
if (!$path) {
return '';
}
$localpath = Hashpath::path($path, 'cache/as', 2); $localpath = Hashpath::path($path, 'cache/as', 2);
if (file_exists($localpath)) { if (file_exists($localpath)) {
return file_get_contents($localpath); return file_get_contents($localpath);
@ -13,11 +16,17 @@ class ObjCache
return ''; return '';
} }
public static function Set($path,$content) { public static function Set($path,$content) {
if (!$path) {
return;
}
$localpath = Hashpath::path($path, 'cache/as', 2); $localpath = Hashpath::path($path, 'cache/as', 2);
file_put_contents($localpath, $content); file_put_contents($localpath, $content);
} }
public static function Delete($path) { public static function Delete($path) {
if (!$path) {
return;
}
$localpath = Hashpath::path($path, 'cache/as', 2); $localpath = Hashpath::path($path, 'cache/as', 2);
if (file_exists($localpath)) { if (file_exists($localpath)) {
unlink($localpath); unlink($localpath);

View file

@ -22,10 +22,10 @@ class ThreadItem
// list of supported reaction emojis - a site can over-ride this via config system.reactions // list of supported reaction emojis - a site can over-ride this via config system.reactions
// Deprecated. Use your operating system or a browser plugin. // Deprecated. Use your operating system or a browser plugin.
private $reactions = ['1f60a','1f44f','1f37e','1f48b','1f61e','2665','1f606','1f62e','1f634','1f61c','1f607','1f608']; private $reactions = ['1f60a','1f44f','1f37e','1f48b','1f61e','2665','1f606','1f62e','1f634','1f61c','1f607','1f608'];
private $toplevel = false; private $toplevel;
private $children = []; private $children = [];
private $parent = null; private $parent = null;
private $conversation = null; private $conversation;
private $redirect_url = null; private $redirect_url = null;
private $owner_url = ''; private $owner_url = '';
private $owner_photo = ''; private $owner_photo = '';
@ -33,7 +33,7 @@ class ThreadItem
private $owner_addr = ''; private $owner_addr = '';
private $owner_censored = false; private $owner_censored = false;
private $wall_to_wall = false; private $wall_to_wall = false;
private $threaded = false; private $threaded;
private $visiting = false; private $visiting = false;
private $channel = null; private $channel = null;
private $display_mode = 'normal'; private $display_mode = 'normal';
@ -98,11 +98,9 @@ class ThreadItem
$item = $this->get_data(); $item = $this->get_data();
$sparkle = '';
$dropping = false; $dropping = false;
$star = false; $star = false;
$is_comment = false; $is_comment = false;
$osparkle = '';
$total_children = $this->count_descendants(); $total_children = $this->count_descendants();
$unseen_comments = ((isset($item['real_uid']) && $item['real_uid']) ? 0 : $this->count_unseen_descendants()); $unseen_comments = ((isset($item['real_uid']) && $item['real_uid']) ? 0 : $this->count_unseen_descendants());
$privacy_warning = false; $privacy_warning = false;
@ -148,7 +146,7 @@ class ThreadItem
$edlink = 'editpost'; $edlink = 'editpost';
if (local_channel() && $observer['xchan_hash'] === $item['author_xchan']) { if (local_channel() && $observer['xchan_hash'] === $item['author_xchan']) {
$edpost = array(z_root() . '/' . $edlink . '/' . $item['id'], t('Edit')); $edpost = [z_root() . '/' . $edlink . '/' . $item['id'], t('Edit')];
} else { } else {
$edpost = false; $edpost = false;
} }
@ -183,32 +181,32 @@ class ThreadItem
if ($dropping) { if ($dropping) {
$drop = array( $drop = [
'dropping' => $dropping, 'dropping' => $dropping,
'delete' => t('Delete'), 'delete' => t('Delete'),
); ];
} elseif (is_site_admin()) { } elseif (is_site_admin()) {
$drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ]; $drop = [ 'dropping' => true, 'delete' => t('Admin Delete') ];
} }
if (isset($observer_is_pageowner) && $observer_is_pageowner) { if (isset($observer_is_pageowner) && $observer_is_pageowner) {
$multidrop = array( $multidrop = [
'select' => t('Select'), 'select' => t('Select'),
); ];
} }
$filer = ((($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid', $item))) ? t('Save to Folder') : false); $filer = ((($conv->get_profile_owner() == local_channel()) && (! array_key_exists('real_uid', $item))) ? t('Save to Folder') : false);
$large_avatar = $item['author']['xchan_photo_l'];
$profile_avatar = $item['author']['xchan_photo_m']; $profile_avatar = $item['author']['xchan_photo_m'];
$profile_link = chanlink_hash($item['author_xchan']); $profile_link = chanlink_hash($item['author_xchan']);
$profile_name = $item['author']['xchan_name']; $profile_name = $item['author']['xchan_name'];
$profile_addr = $item['author']['xchan_addr'] ? $item['author']['xchan_addr'] : $item['author']['xchan_url']; $profile_addr = $item['author']['xchan_addr'] ?: $item['author']['xchan_url'];
$location = format_location($item); $location = format_location($item);
$isevent = false; $isevent = false;
$attend = null; $attend = null;
$canvote = false;
// process action responses - e.g. like/dislike/attend/agree/whatever // process action responses - e.g. like/dislike/attend/agree/whatever
$response_verbs = [ 'like', 'dislike' ]; $response_verbs = [ 'like', 'dislike' ];
@ -219,7 +217,7 @@ class ThreadItem
$response_verbs[] = 'attendmaybe'; $response_verbs[] = 'attendmaybe';
if ($this->is_commentable() && $observer) { if ($this->is_commentable() && $observer) {
$isevent = true; $isevent = true;
$attend = array( t('I will attend'), t('I will not attend'), t('I might attend')); $attend = [t('I will attend'), t('I will not attend'), t('I might attend')];
$undo_attend = t('Undo attendance'); $undo_attend = t('Undo attendance');
} }
} }
@ -272,7 +270,7 @@ class ThreadItem
if (local_channel() && ($conv->get_profile_owner() == local_channel() || intval($item['item_private']) === 0)) { if (local_channel() && ($conv->get_profile_owner() == local_channel() || intval($item['item_private']) === 0)) {
$star = [ $star = [
'toggle' => t('Save'), 'toggle' => t('Save'),
'isstarred' => ((intval($item['item_starred'])) ? true : false), 'isstarred' => (bool) $item['item_starred']
]; ];
} }
} else { } else {
@ -286,10 +284,10 @@ class ThreadItem
if ($conv->get_profile_owner() == local_channel()) { if ($conv->get_profile_owner() == local_channel()) {
$tagger = array( $tagger = [
'tagit' => t("Add Tag"), 'tagit' => t("Add Tag"),
'classtagger' => "", 'classtagger' => "",
); ];
} }
$has_bookmarks = false; $has_bookmarks = false;
@ -307,8 +305,8 @@ class ThreadItem
} }
if ($this->is_commentable() && $observer) { if ($this->is_commentable() && $observer) {
$like = array( t('I like this'), t('Undo like')); $like = [t('I like this'), t('Undo like')];
$dislike = array( t('I don\'t like this'), t('Undo dislike') ); $dislike = [t('I don\'t like this'), t('Undo dislike')];
} }
$share = $embed = EMPTY_STR; $share = $embed = EMPTY_STR;
@ -372,7 +370,12 @@ class ThreadItem
$pinned_items = ($allowed_type ? get_pconfig($item['uid'], 'pinned', $item['item_type'], []) : []); $pinned_items = ($allowed_type ? get_pconfig($item['uid'], 'pinned', $item['item_type'], []) : []);
$pinned = ((! empty($pinned_items) && in_array($item['mid'], $pinned_items)) ? true : false); $pinned = ((! empty($pinned_items) && in_array($item['mid'], $pinned_items)) ? true : false);
$tmp_item = array( $locicon = ($item['verb'] === 'Arrive') ? '<i class="fa fa-fw fa-sign-in"></i>&nbsp' : '';
if (!$locicon) {
$locicon = ($item['verb'] === 'Leave') ? '<i class="fa fa-fw fa-sign-out"></i>&nbsp' : '';
}
$tmp_item = [
'template' => $this->get_template(), 'template' => $this->get_template(),
'mode' => $mode, 'mode' => $mode,
'item_type' => intval($item['item_type']), 'item_type' => intval($item['item_type']),
@ -394,7 +397,6 @@ class ThreadItem
'undo_attend' => $undo_attend, 'undo_attend' => $undo_attend,
'consensus' => '', 'consensus' => '',
'conlabels' => '', 'conlabels' => '',
'canvote' => $canvote,
'linktitle' => sprintf(t('View %s\'s profile - %s'), $profile_name, (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url'])), 'linktitle' => sprintf(t('View %s\'s profile - %s'), $profile_name, (($item['author']['xchan_addr']) ? $item['author']['xchan_addr'] : $item['author']['xchan_url'])),
'olinktitle' => sprintf(t('View %s\'s profile - %s'), $this->get_owner_name(), (($this->get_owner_addr()) ? $this->get_owner_addr() : $this->get_owner_url())), 'olinktitle' => sprintf(t('View %s\'s profile - %s'), $this->get_owner_name(), (($this->get_owner_addr()) ? $this->get_owner_addr() : $this->get_owner_url())),
'llink' => $item['llink'], 'llink' => $item['llink'],
@ -411,9 +413,8 @@ class ThreadItem
'myconv' => $myconv, 'myconv' => $myconv,
'name' => $profile_name, 'name' => $profile_name,
'thumb' => $profile_avatar, 'thumb' => $profile_avatar,
'osparkle' => $osparkle, 'large_avatar' => $large_avatar,
'sparkle' => $sparkle, 'title' => $locicon . $item['title'],
'title' => $item['title'],
'title_tosource' => get_pconfig($conv->get_profile_owner(), 'system', 'title_tosource'), 'title_tosource' => get_pconfig($conv->get_profile_owner(), 'system', 'title_tosource'),
'ago' => relative_date($item['created']), 'ago' => relative_date($item['created']),
'app' => $item['app'], 'app' => $item['app'],
@ -500,9 +501,9 @@ class ThreadItem
'thread_level' => $thread_level, 'thread_level' => $thread_level,
'indentpx' => intval(get_pconfig(local_channel(), 'system', 'thread_indent_px', get_config('system', 'thread_indent_px', 0))), 'indentpx' => intval(get_pconfig(local_channel(), 'system', 'thread_indent_px', get_config('system', 'thread_indent_px', 0))),
'thread_max' => intval(get_config('system', 'thread_maxlevel', 20)) + 1 'thread_max' => intval(get_config('system', 'thread_maxlevel', 20)) + 1
); ];
$arr = array('item' => $item, 'output' => $tmp_item); $arr = ['item' => $item, 'output' => $tmp_item];
Hook::call('display_item', $arr); Hook::call('display_item', $arr);
$result = $arr['output']; $result = $arr['output'];
@ -735,8 +736,6 @@ class ThreadItem
*/ */
public function set_conversation($conv) public function set_conversation($conv)
{ {
$previous_mode = ($this->conversation ? $this->conversation->get_mode() : '');
$this->conversation = $conv; $this->conversation = $conv;
// Set it on our children too // Set it on our children too
@ -832,33 +831,6 @@ class ThreadItem
return $total; return $total;
} }
private function label_descendants($count = 0)
{
if (! array_key_exists('sequence', $this->data)) {
if ($count) {
$count++;
}
$this->data['sequence'] = $count;
}
logger('labelled: ' . print_r($this->data, true), LOGGER_DATA);
$children = $this->get_children();
$total = count($children);
if ($total > 0) {
foreach ($children as $child) {
if (! visible_activity($child->data)) {
continue;
}
if (! array_key_exists('sequence', $this->data)) {
$count++;
$child->data['sequence'] = $count;
logger('labelled_child: ' . print_r($child->data, true), LOGGER_DATA);
}
$child->label_descendants($count);
}
}
}
private function count_unseen_descendants() private function count_unseen_descendants()
{ {
$children = $this->get_children(); $children = $this->get_children();
@ -913,7 +885,7 @@ class ThreadItem
$observer = $conv->get_observer(); $observer = $conv->get_observer();
$arr = array('comment_buttons' => '','id' => $this->get_id()); $arr = ['comment_buttons' => '','id' => $this->get_id()];
Hook::call('comment_buttons', $arr); Hook::call('comment_buttons', $arr);
$comment_buttons = $arr['comment_buttons']; $comment_buttons = $arr['comment_buttons'];
@ -922,7 +894,7 @@ class ThreadItem
$comment_box = replace_macros($template, array( $comment_box = replace_macros($template, [
'$return_path' => '', '$return_path' => '',
'$threaded' => $this->is_threaded(), '$threaded' => $this->is_threaded(),
'$jsreload' => $conv->reload, '$jsreload' => $conv->reload,
@ -950,20 +922,20 @@ class ThreadItem
'$reset' => t('Reset'), '$reset' => t('Reset'),
'$indent' => $indent, '$indent' => $indent,
'$can_upload' => (perm_is_allowed($conv->get_profile_owner(), get_observer_hash(), 'write_storage') && $conv->is_uploadable()), '$can_upload' => (perm_is_allowed($conv->get_profile_owner(), get_observer_hash(), 'write_storage') && $conv->is_uploadable()),
'$feature_encrypt' => ((Apps::system_app_installed($conv->get_profile_owner(), 'Secrets')) ? true : false), '$feature_encrypt' => Apps::system_app_installed($conv->get_profile_owner(), 'Secrets'),
'$feature_markup' => ((Apps::system_app_installed($conv->get_profile_owner(), 'Markup')) ? true : false), '$feature_markup' => Apps::system_app_installed($conv->get_profile_owner(), 'Markup'),
'$encrypt' => t('Encrypt text'), '$encrypt' => t('Encrypt text'),
'$cipher' => $conv->get_cipher(), '$cipher' => $conv->get_cipher(),
'$sourceapp' => App::$sourcename, '$sourceapp' => App::$sourcename,
'$observer' => get_observer_hash(), '$observer' => get_observer_hash(),
'$anoncomments' => ((($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(), '', 'post_comments')) ? true : false), '$anoncomments' => ($conv->get_mode() === 'channel' || $conv->get_mode() === 'display') && perm_is_allowed($conv->get_profile_owner(), '', 'post_comments'),
'$anonname' => [ 'anonname', t('Your full name (required)') ], '$anonname' => [ 'anonname', t('Your full name (required)') ],
'$anonmail' => [ 'anonmail', t('Your email address (required)') ], '$anonmail' => [ 'anonmail', t('Your email address (required)') ],
'$anonurl' => [ 'anonurl', t('Your website URL (optional)') ], '$anonurl' => [ 'anonurl', t('Your website URL (optional)') ],
'$auto_save_draft' => $feature_auto_save_draft, '$auto_save_draft' => $feature_auto_save_draft,
'$save' => $permanent_draft, '$save' => $permanent_draft,
'$top' => $this->is_toplevel() '$top' => $this->is_toplevel()
)); ]);
return $comment_box; return $comment_box;
} }
@ -1026,7 +998,7 @@ class ThreadItem
'photo' => $child['author']['xchan_photo_m'], 'photo' => $child['author']['xchan_photo_m'],
'name' => $child['author']['xchan_name'], 'name' => $child['author']['xchan_name'],
'addr' => $child['author']['xchan_addr'], 'addr' => $child['author']['xchan_addr'],
'censored' => (($child['author']['xchan_censored'] || $child['author']['abook_censor']) ? true : false) 'censored' => $child['author']['xchan_censored'] || $child['author']['abook_censor']
]; ];
} }
if ($child['children']) { if ($child['children']) {

View file

@ -150,6 +150,9 @@ class Url {
} }
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $validate_ssl); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $validate_ssl);
if (! $validate_ssl) {
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
}
$prx = @get_config('system', 'proxy'); $prx = @get_config('system', 'proxy');
if (strlen($prx)) { if (strlen($prx)) {
@ -356,6 +359,9 @@ class Url {
} }
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $validate_ssl); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $validate_ssl);
if (! $validate_ssl) {
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
}
$prx = get_config('system', 'proxy'); $prx = get_config('system', 'proxy');
if (strlen($prx)) { if (strlen($prx)) {

View file

@ -277,11 +277,7 @@ class Activity extends Controller
http_status_exit(404, 'Not found'); http_status_exit(404, 'Not found');
} }
$x = array_merge(['@context' => [ $x = array_merge(Activity::ap_context(), $i);
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
ZlibActivity::ap_schema()
]], $i);
$headers = []; $headers = [];
$headers['Content-Type'] = 'application/x-nomad+json'; $headers['Content-Type'] = 'application/x-nomad+json';

View file

@ -163,6 +163,10 @@ class Accounts
if ($users) { if ($users) {
for ($x = 0; $x < count($users); $x++) { for ($x = 0; $x < count($users); $x++) {
$users[$x]['account_lastlog'] = datetime_convert(to: date_default_timezone_get(), datetime: $users[$x]['account_lastlog']);
$users[$x]['account_created'] = datetime_convert(to: date_default_timezone_get(), datetime: $users[$x]['account_created']);
$users[$x]['account_expires'] = datetime_convert(to: date_default_timezone_get(), datetime: $users[$x]['account_expires']);
$channel_arr = explode(' ', $users[$x]['channels']); $channel_arr = explode(' ', $users[$x]['channels']);
if ($channel_arr) { if ($channel_arr) {
$linked = []; $linked = [];

View file

@ -40,16 +40,6 @@ class Channels
} }
notice(sprintf(tt("%s channel censored/uncensored", "%s channels censored/uncensored", count($channels)), count($channels))); notice(sprintf(tt("%s channel censored/uncensored", "%s channels censored/uncensored", count($channels)), count($channels)));
} }
if (x($_POST, 'page_channels_code')) {
foreach ($channels as $uid) {
q(
"UPDATE channel SET channel_pageflags = ( channel_pageflags $xor %d ) where channel_id = %d",
intval(PAGE_ALLOWCODE),
intval($uid)
);
}
notice(sprintf(tt("%s channel code allowed/disallowed", "%s channels code allowed/disallowed", count($channels)), count($channels)));
}
if (x($_POST, 'page_channels_delete')) { if (x($_POST, 'page_channels_delete')) {
foreach ($channels as $uid) { foreach ($channels as $uid) {
Channel::channel_remove($uid, true); Channel::channel_remove($uid, true);
@ -105,20 +95,6 @@ class Channels
} }
break; break;
case "code":
{
check_form_security_token_redirectOnErr('/admin/channels', 'admin_channels', 't');
$pflags = $channel[0]['channel_pageflags'] ^ PAGE_ALLOWCODE;
q(
"UPDATE channel SET channel_pageflags = %d where channel_id = %d",
intval($pflags),
intval($uid)
);
notice(sprintf((($pflags & PAGE_ALLOWCODE) ? t("Channel '%s' code allowed") : t("Channel '%s' code disallowed")), $channel[0]['channel_name'] . ' (' . $channel[0]['channel_address'] . ')') . EOL);
}
break;
default: default:
break; break;
} }
@ -156,12 +132,6 @@ class Channels
$channels[$x]['blocked'] = false; $channels[$x]['blocked'] = false;
} }
if ($channels[$x]['channel_pageflags'] & PAGE_ALLOWCODE) {
$channels[$x]['allowcode'] = true;
} else {
$channels[$x]['allowcode'] = false;
}
$channels[$x]['channel_link'] = z_root() . '/channel/' . $channels[$x]['channel_address']; $channels[$x]['channel_link'] = z_root() . '/channel/' . $channels[$x]['channel_address'];
} }
} }
@ -177,8 +147,6 @@ class Channels
'$delete' => t('Delete'), '$delete' => t('Delete'),
'$block' => t('Censor'), '$block' => t('Censor'),
'$unblock' => t('Uncensor'), '$unblock' => t('Uncensor'),
'$code' => t('Allow Code'),
'$uncode' => t('Disallow Code'),
'$h_channels' => t('Channel'), '$h_channels' => t('Channel'),
'$base' => $base, '$base' => $base,
'$odir' => $odir, '$odir' => $odir,

View file

@ -24,6 +24,9 @@ class Security
$use_hs2019 = ((x($_POST, 'use_hs2019')) ? intval($_POST['use_hs2019']) : 0); $use_hs2019 = ((x($_POST, 'use_hs2019')) ? intval($_POST['use_hs2019']) : 0);
set_config('system', 'use_hs2019', $use_hs2019); set_config('system', 'use_hs2019', $use_hs2019);
$use_fep5624 = ((x($_POST, 'use_fep5624')) ? intval($_POST['use_fep5624']) : 0);
set_config('system', 'use_fep5624', $use_fep5624);
$block_public_search = ((x($_POST, 'block_public_search')) ? 1 : 0); $block_public_search = ((x($_POST, 'block_public_search')) ? 1 : 0);
set_config('system', 'block_public_search', $block_public_search); set_config('system', 'block_public_search', $block_public_search);
@ -144,6 +147,7 @@ class Security
'$cloud_noroot' => ['cloud_noroot', t('Provide a cloud root directory'), 1 - intval(get_config('system', 'cloud_disable_siteroot', true)), t('The cloud root directory lists all channel names which provide public files. Otherwise only the names of connections are shown.')], '$cloud_noroot' => ['cloud_noroot', t('Provide a cloud root directory'), 1 - intval(get_config('system', 'cloud_disable_siteroot', true)), t('The cloud root directory lists all channel names which provide public files. Otherwise only the names of connections are shown.')],
'$cloud_disksize' => ['cloud_disksize', t('Show total disk space available to cloud uploads'), intval(get_config('system', 'cloud_report_disksize')), ''], '$cloud_disksize' => ['cloud_disksize', t('Show total disk space available to cloud uploads'), intval(get_config('system', 'cloud_report_disksize')), ''],
'$use_hs2019' => ['use_hs2019', t('Use hs2019 HTTP-Signature specification'), intval(get_config('system', 'use_hs2019', false)), t('This is not yet supported by many fediverse servers.')], '$use_hs2019' => ['use_hs2019', t('Use hs2019 HTTP-Signature specification'), intval(get_config('system', 'use_hs2019', false)), t('This is not yet supported by many fediverse servers.')],
'$use_fep5624' => ['use_fep5624', t('Require FEP-5624 comment approvals'), intval(get_config('system', 'use_fep5624', false)), t('This is not yet supported by many fediverse servers.')],
'$thumbnail_security' => ['thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system', 'thumbnail_security', 0), t("WARNING: SVG images may contain malicious code.")], '$thumbnail_security' => ['thumbnail_security', t("Allow SVG thumbnails in file browser"), get_config('system', 'thumbnail_security', 0), t("WARNING: SVG images may contain malicious code.")],
'$inline_pdf' => ['inline_pdf', t("Allow embedded (inline) PDF files"), get_config('system', 'inline_pdf', 0), ''], '$inline_pdf' => ['inline_pdf', t("Allow embedded (inline) PDF files"), get_config('system', 'inline_pdf', 0), ''],

View file

@ -11,9 +11,7 @@ class Apschema extends Controller
public function init() public function init()
{ {
$arr = [ $arr = Activity::ap_context();
'@context' => array_merge(['as' => 'https://www.w3.org/ns/activitystreams#'], Activity::ap_schema())
];
header('Content-Type: application/ld+json'); header('Content-Type: application/ld+json');
echo json_encode($arr, JSON_UNESCAPED_SLASHES); echo json_encode($arr, JSON_UNESCAPED_SLASHES);

View file

@ -10,6 +10,7 @@ use Code\Identity\OAuth2Server;
use Code\Identity\OAuth2Storage; use Code\Identity\OAuth2Storage;
use OAuth2\Request; use OAuth2\Request;
use OAuth2\Response; use OAuth2\Response;
use OAuth2\GrantType;
use Code\Render\Theme; use Code\Render\Theme;
@ -55,7 +56,12 @@ class Authorize extends Controller
} }
$storage = new OAuth2Storage(DBA::$dba->db); $storage = new OAuth2Storage(DBA::$dba->db);
$s = new OAuth2Server($storage); $server = new OAuth2Server($storage);
// Add the "Client Credentials" grant type (it is the simplest of the grant types)
$server->addGrantType(new GrantType\ClientCredentials($storage));
// Add the "Authorization Code" grant type (this is where the oauth magic happens)
$server->addGrantType(new GrantType\AuthorizationCode($storage));
// TODO: The automatic client registration protocol below should adhere more // TODO: The automatic client registration protocol below should adhere more
// closely to "OAuth 2.0 Dynamic Client Registration Protocol" defined // closely to "OAuth 2.0 Dynamic Client Registration Protocol" defined
@ -93,7 +99,12 @@ class Authorize extends Controller
$client = $storage->getClientDetails($client_id); $client = $storage->getClientDetails($client_id);
logger('client: ' . print_r($client, true), LOGGER_DATA); logger('client: ' . print_r($client, true), LOGGER_DATA);
logger('user_id: ' . $user_id);
if (!$channel || !$user_id) {
// This is fatal, but let it fall through and send a response.
// Log it to have a record of the reason why it's going to die.
logger('not logged in');
}
if ($client) { if ($client) {
if (intval($client['user_id']) === 0 || intval($client['user_id']) === intval($user_id)) { if (intval($client['user_id']) === 0 || intval($client['user_id']) === intval($user_id)) {
$client_found = true; $client_found = true;
@ -106,7 +117,6 @@ class Authorize extends Controller
$grant_types = $client['grant_types']; $grant_types = $client['grant_types'];
// Client apps are registered per channel // Client apps are registered per channel
logger('client_id: ' . $client_id); logger('client_id: ' . $client_id);
logger('client_secret: ' . $client_secret); logger('client_secret: ' . $client_secret);
logger('redirect_uri: ' . $redirect_uri); logger('redirect_uri: ' . $redirect_uri);
@ -126,14 +136,15 @@ class Authorize extends Controller
$response->setParameter('client_secret', $client['client_secret']); $response->setParameter('client_secret', $client['client_secret']);
// validate the authorize request // validate the authorize request
if (!$s->validateAuthorizeRequest($request, $response)) { if (!$server->validateAuthorizeRequest($request, $response)) {
logger('oauth2 authorize validation failed');
$response->send(); $response->send();
killme(); killme();
} }
// print the authorization code if the user has authorized your client // print the authorization code if the user has authorized your client
$is_authorized = ($_POST['authorize'] === 'allow'); $is_authorized = ($_POST['authorize'] === 'allow');
$s->handleAuthorizeRequest($request, $response, $is_authorized, $user_id); $server->handleAuthorizeRequest($request, $response, $is_authorized, $user_id);
if ($is_authorized) { if ($is_authorized) {
$code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=') + 5, 40); $code = substr($response->getHttpHeader('Location'), strpos($response->getHttpHeader('Location'), 'code=') + 5, 40);
logger('Authorization Code: ' . $code); logger('Authorization Code: ' . $code);

View file

@ -3,6 +3,8 @@
namespace Code\Module; namespace Code\Module;
use App; use App;
use Code\Access\PermissionRoles;
use Code\Lib\AbConfig;
use Code\Web\Controller; use Code\Web\Controller;
use Code\Lib\Libzot; use Code\Lib\Libzot;
use Code\Lib\Libsync; use Code\Lib\Libsync;
@ -103,11 +105,9 @@ class Connedit extends Controller
} }
$autoperms = null; $autoperms = null;
$is_self = false;
if (intval($orig_record['abook_self'])) { if (intval($orig_record['abook_self'])) {
$autoperms = intval($_POST['autoperms']); $autoperms = intval($_POST['autoperms']);
$is_self = true;
} }
$profile_id = ((array_key_exists('profile_assign', $_POST)) ? $_POST['profile_assign'] : $orig_record['abook_profile']); $profile_id = ((array_key_exists('profile_assign', $_POST)) ? $_POST['profile_assign'] : $orig_record['abook_profile']);
@ -228,6 +228,16 @@ class Connedit extends Controller
} }
} }
// Provide default "their_perms" if not provided already. .
$their_perms = AbConfig::Get($channel['channel_id'], App::$poi['abook_xchan'], 'system', 'their_perms', '');
if (! $their_perms) {
$x = PermissionRoles::role_perms('social');
$p = Permissions::FilledPerms($x['perms_connect']);
$their_perms = Permissions::serialise($p);
AbConfig::Set($channel['channel_id'], App::$poi['abook_xchan'], 'system', 'their_perms', $their_perms);
}
// Check if settings permit ("post new friend activity" is allowed, and // Check if settings permit ("post new friend activity" is allowed, and
// friends in general or this friend in particular aren't hidden) // friends in general or this friend in particular aren't hidden)
// and send out a new friend activity // and send out a new friend activity
@ -548,84 +558,84 @@ class Connedit extends Controller
} }
} }
$tools = array( $tools = [
'view' => array( 'view' => [
'label' => t('View Profile'), 'label' => t('View Profile'),
'url' => chanlink_cid($contact['abook_id']), 'url' => chanlink_cid($contact['abook_id']),
'sel' => '', 'sel' => '',
'title' => sprintf(t('View %s\'s profile'), $contact['xchan_name']), 'title' => sprintf(t('View %s\'s profile'), $contact['xchan_name']),
), ],
'refresh' => array( 'refresh' => [
'label' => t('Refresh Permissions'), 'label' => t('Refresh Permissions'),
'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/refresh', 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/refresh',
'sel' => '', 'sel' => '',
'title' => t('Fetch updated permissions'), 'title' => t('Fetch updated permissions'),
), ],
'rephoto' => array( 'rephoto' => [
'label' => t('Refresh Photo'), 'label' => t('Refresh Photo'),
'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/resetphoto', 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/resetphoto',
'sel' => '', 'sel' => '',
'title' => t('Fetch updated photo'), 'title' => t('Fetch updated photo'),
), ],
'recent' => array( 'recent' => [
'label' => t('Recent Activity'), 'label' => t('Recent Activity'),
'url' => z_root() . '/stream/?f=&cid=' . $contact['abook_id'], 'url' => z_root() . '/stream/?f=&cid=' . $contact['abook_id'],
'sel' => '', 'sel' => '',
'title' => t('View recent posts and comments'), 'title' => t('View recent posts and comments'),
), ],
'block' => array( 'block' => [
'label' => (intval($contact['abook_blocked']) ? t('Unblock') : t('Block')), 'label' => (intval($contact['abook_blocked']) ? t('Unblock') : t('Block')),
'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/block', 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/block',
'sel' => (intval($contact['abook_blocked']) ? 'active' : ''), 'sel' => (intval($contact['abook_blocked']) ? 'active' : ''),
'title' => t('Block (or Unblock) all communications with this connection'), 'title' => t('Block (or Unblock) all communications with this connection'),
'info' => (intval($contact['abook_blocked']) ? t('This connection is blocked') : ''), 'info' => (intval($contact['abook_blocked']) ? t('This connection is blocked') : ''),
), ],
'ignore' => array( 'ignore' => [
'label' => (intval($contact['abook_ignored']) ? t('Unignore') : t('Ignore')), 'label' => (intval($contact['abook_ignored']) ? t('Unignore') : t('Ignore')),
'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/ignore', 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/ignore',
'sel' => (intval($contact['abook_ignored']) ? 'active' : ''), 'sel' => (intval($contact['abook_ignored']) ? 'active' : ''),
'title' => t('Ignore (or Unignore) all inbound communications from this connection'), 'title' => t('Ignore (or Unignore) all inbound communications from this connection'),
'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored') : ''), 'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored') : ''),
), ],
'censor' => array( 'censor' => [
'label' => (intval($contact['abook_censor']) ? t('Uncensor') : t('Censor')), 'label' => (intval($contact['abook_censor']) ? t('Uncensor') : t('Censor')),
'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/censor', 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/censor',
'sel' => (intval($contact['abook_censor']) ? 'active' : ''), 'sel' => (intval($contact['abook_censor']) ? 'active' : ''),
'title' => t('Censor (or Uncensor) images from this connection'), 'title' => t('Censor (or Uncensor) images from this connection'),
'info' => (intval($contact['abook_censor']) ? t('This connection is censored') : ''), 'info' => (intval($contact['abook_censor']) ? t('This connection is censored') : ''),
), ],
'archive' => array( 'archive' => [
'label' => (intval($contact['abook_archived']) ? t('Unarchive') : t('Archive')), 'label' => (intval($contact['abook_archived']) ? t('Unarchive') : t('Archive')),
'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/archive', 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/archive',
'sel' => (intval($contact['abook_archived']) ? 'active' : ''), 'sel' => (intval($contact['abook_archived']) ? 'active' : ''),
'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content'), 'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content'),
'info' => (intval($contact['abook_archived']) ? t('This connection is archived') : ''), 'info' => (intval($contact['abook_archived']) ? t('This connection is archived') : ''),
), ],
'hide' => array( 'hide' => [
'label' => (intval($contact['abook_hidden']) ? t('Unhide') : t('Hide')), 'label' => (intval($contact['abook_hidden']) ? t('Unhide') : t('Hide')),
'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/hide', 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/hide',
'sel' => (intval($contact['abook_hidden']) ? 'active' : ''), 'sel' => (intval($contact['abook_hidden']) ? 'active' : ''),
'title' => t('Hide or Unhide this connection from your other connections'), 'title' => t('Hide or Unhide this connection from your other connections'),
'info' => (intval($contact['abook_hidden']) ? t('This connection is hidden') : ''), 'info' => (intval($contact['abook_hidden']) ? t('This connection is hidden') : ''),
), ],
'delete' => array( 'delete' => [
'label' => t('Delete'), 'label' => t('Delete'),
'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/drop', 'url' => z_root() . '/connedit/' . $contact['abook_id'] . '/drop',
'sel' => '', 'sel' => '',
'title' => t('Delete this connection'), 'title' => t('Delete this connection'),
), ],
); ];
if (in_array($contact['xchan_network'], [ 'zot6', 'nomad' ])) { if (in_array($contact['xchan_network'], [ 'zot6', 'nomad' ])) {
@ -686,11 +696,11 @@ class Connedit extends Controller
$slideval = intval($contact['abook_closeness']); $slideval = intval($contact['abook_closeness']);
$slide = replace_macros($slider_tpl, array( $slide = replace_macros($slider_tpl, [
'$min' => 1, '$min' => 1,
'$val' => $slideval, '$val' => $slideval,
'$labels' => $labels, '$labels' => $labels,
)); ]);
} }
if (Apps::system_app_installed(local_channel(), 'Content Filter')) { if (Apps::system_app_installed(local_channel(), 'Content Filter')) {
@ -707,9 +717,9 @@ class Connedit extends Controller
$global_perms = Permissions::Perms(); $global_perms = Permissions::Perms();
$existing = get_all_perms(local_channel(), $contact['abook_xchan'], false); $existing = get_all_perms(local_channel(), $contact['abook_xchan']);
$unapproved = array('pending', t('Approve this connection'), '', t('Accept connection to allow communication'), array(t('No'), t('Yes'))); $unapproved = ['pending', t('Approve this connection'), '', t('Accept connection to allow communication'), [t('No'), t('Yes')]];
$multiprofs = ((Features::enabled(local_channel(), 'multi_profiles')) ? true : false); $multiprofs = ((Features::enabled(local_channel(), 'multi_profiles')) ? true : false);
@ -748,7 +758,7 @@ class Connedit extends Controller
$thisperm = "1"; $thisperm = "1";
} }
$perms[] = array('perms_' . $k, $v, ((array_key_exists($k, $their_perms)) ? intval($their_perms[$k]) : ''), $thisperm, $yes_no, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited); $perms[] = ['perms_' . $k, $v, ((array_key_exists($k, $their_perms)) ? intval($their_perms[$k]) : ''), $thisperm, $yes_no, (($checkinherited & PERMS_SPECIFIC) ? '' : '1'), '', $checkinherited];
} }
$current_permcat = EMPTY_STR; $current_permcat = EMPTY_STR;
@ -789,7 +799,7 @@ class Connedit extends Controller
$o .= replace_macros($tpl, [ $o .= replace_macros($tpl, [
'$header' => (($self) ? t('Connection Default Permissions') : sprintf(t('Connection: %s'), $contact['xchan_name']) . (($contact['abook_alias']) ? ' &lt;' . $contact['abook_alias'] . '&gt;' : '')), '$header' => (($self) ? t('Connection Default Permissions') : sprintf(t('Connection: %s'), $contact['xchan_name']) . (($contact['abook_alias']) ? ' &lt;' . $contact['abook_alias'] . '&gt;' : '')),
'$autoperms' => array('autoperms', t('Apply these permissions automatically'), ((get_pconfig(local_channel(), 'system', 'autoperms')) ? 1 : 0), t('Connection requests will be approved without your interaction'), $yes_no), '$autoperms' => ['autoperms', t('Apply these permissions automatically'), ((get_pconfig(local_channel(), 'system', 'autoperms')) ? 1 : 0), t('Connection requests will be approved without your interaction'), $yes_no],
'$permcat' => ['permcat', t('Permission role'), $current_permcat, '<span class="loading invisible">' . t('Loading') . '<span class="jumping-dots"><span class="dot-1">.</span><span class="dot-2">.</span><span class="dot-3">.</span></span></span>', $permcats], '$permcat' => ['permcat', t('Permission role'), $current_permcat, '<span class="loading invisible">' . t('Loading') . '<span class="jumping-dots"><span class="dot-1">.</span><span class="dot-2">.</span><span class="dot-3">.</span></span></span>', $permcats],
'$permcat_new' => t('Add permission role'), '$permcat_new' => t('Add permission role'),
'$permcat_enable' => Apps::system_app_installed(local_channel(),'Roles'), '$permcat_enable' => Apps::system_app_installed(local_channel(),'Roles'),
@ -811,9 +821,9 @@ class Connedit extends Controller
'$lbl_slider' => t('Slide to adjust your degree of friendship'), '$lbl_slider' => t('Slide to adjust your degree of friendship'),
'$connfilter' => Apps::system_app_installed(local_channel(), 'Content Filter'), '$connfilter' => Apps::system_app_installed(local_channel(), 'Content Filter'),
'$connfilter_label' => t('Custom Filter'), '$connfilter_label' => t('Custom Filter'),
'$incl' => array('abook_incl', t('Only import posts with this text'), $contact['abook_incl'], t('words one per line or #tags, $categories, /patterns/, or lang=xx, leave blank to import all posts')), '$incl' => ['abook_incl', t('Only import posts with this text'), $contact['abook_incl'], t('words one per line or #tags, $categories, /patterns/, or lang=xx, leave blank to import all posts')],
'$excl' => array('abook_excl', t('Do not import posts with this text'), $contact['abook_excl'], t('words one per line or #tags, $categories, /patterns/, or lang=xx, leave blank to import all posts')), '$excl' => ['abook_excl', t('Do not import posts with this text'), $contact['abook_excl'], t('words one per line or #tags, $categories, /patterns/, or lang=xx, leave blank to import all posts')],
'$alias' => array('abook_alias', t('Nickname'), $contact['abook_alias'], t('optional - allows you to search by a name that you have chosen')), '$alias' => ['abook_alias', t('Nickname'), $contact['abook_alias'], t('optional - allows you to search by a name that you have chosen')],
'$slide' => $slide, '$slide' => $slide,
'$affinity' => $affinity, '$affinity' => $affinity,
'$pending_label' => t('Connection Pending Approval'), '$pending_label' => t('Connection Pending Approval'),
@ -866,7 +876,7 @@ class Connedit extends Controller
'$country' => t('Country') '$country' => t('Country')
]); ]);
$arr = array('contact' => $contact, 'output' => $o); $arr = ['contact' => $contact, 'output' => $o];
Hook::call('contact_edit', $arr); Hook::call('contact_edit', $arr);

View file

@ -34,7 +34,7 @@ class Ap_probe extends Controller
} }
} }
$j = Activity::fetch($resource, $channel, true); $j = Activity::fetch($resource, $channel, false,true);
if ($j) { if ($j) {
$html .= '<pre>' . str_replace('\\n', "\n", htmlspecialchars(json_encode($j, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT))) . '</pre>'; $html .= '<pre>' . str_replace('\\n', "\n", htmlspecialchars(json_encode($j, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT))) . '</pre>';

View file

@ -20,12 +20,16 @@ class Xchan extends Controller
if (x($_GET, 'addr')) { if (x($_GET, 'addr')) {
$addr = trim($_GET['addr']); $addr = trim($_GET['addr']);
$h = q("select * from hubloc where hubloc_hash like '%s%%' or hubloc_addr = '%s'",
$r = q(
"select * from xchan where xchan_hash like '%s%%' or xchan_addr = '%s' group by xchan_hash",
dbesc($addr), dbesc($addr),
dbesc($addr) dbesc($addr)
); );
if ($h) {
$r = q(
"select * from xchan where xchan_hash = '%s'",
dbesc($h[0]['hubloc_hash']),
);
}
if ($r) { if ($r) {
foreach ($r as $rr) { foreach ($r as $rr) {

View file

@ -298,11 +298,7 @@ class Directory extends Controller
//$i = Activity::encode_actor_collection($items, 'search?' . $saved_id , 'OrderedCollection', true, count($items)); //$i = Activity::encode_actor_collection($items, 'search?' . $saved_id , 'OrderedCollection', true, count($items));
$x = array_merge(['@context' => [ $x = array_merge(Activity::ap_context(), $i);
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
Activity::ap_schema()
]], $i);
$headers = []; $headers = [];
$headers['Content-Type'] = 'application/x-nomad+json'; $headers['Content-Type'] = 'application/x-nomad+json';

View file

@ -469,7 +469,7 @@ class Display extends Controller
if ($item['item_private']) { if ($item['item_private']) {
continue; continue;
} }
$atom .= atom_entry($item, $type, [], [], true, '', false); $atom .= atom_entry($item, $type, [], [], true, '');
} }
} }

View file

@ -96,7 +96,7 @@ class Editpost extends Controller
$mentions = get_terms_oftype($item['term'], TERM_MENTION); $mentions = get_terms_oftype($item['term'], TERM_MENTION);
if ($mentions) { if ($mentions) {
foreach ($mentions as $mention) { foreach ($mentions as $mention) {
if (strlen($hidden_mentions) && strpos($item['body'], $mention['url']) === false ) { if (strlen($hidden_mentions) && !str_contains($item['body'], $mention['url'])) {
$hidden_mentions .= ', '; $hidden_mentions .= ', ';
} }
$hidden_mentions .= '@{' . $mention['url'] . '}'; $hidden_mentions .= '@{' . $mention['url'] . '}';
@ -146,7 +146,7 @@ class Editpost extends Controller
'hide_voting' => true, 'hide_voting' => true,
'hide_future' => true, 'hide_future' => true,
'hide_location' => true, 'hide_location' => true,
'is_draft' => ((intval($item['item_unpublished'])) ? true : false), 'is_draft' => (bool)intval($item['item_unpublished']),
'parent' => (($item['mid'] === $item['parent_mid']) ? 0 : $item['parent']), 'parent' => (($item['mid'] === $item['parent_mid']) ? 0 : $item['parent']),
'mimetype' => $item['mimetype'], 'mimetype' => $item['mimetype'],
'ptyp' => $item['obj_type'], 'ptyp' => $item['obj_type'],
@ -157,7 +157,7 @@ class Editpost extends Controller
'title' => htmlspecialchars_decode($item['title'], ENT_COMPAT), 'title' => htmlspecialchars_decode($item['title'], ENT_COMPAT),
'category' => $category, 'category' => $category,
'hidden_mentions' => $hidden_mentions, 'hidden_mentions' => $hidden_mentions,
'showacl' => ((intval($item['item_unpublished'])) ? true : false), 'showacl' => (bool)intval($item['item_unpublished']),
'lockstate' => (($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) ? 'lock' : 'unlock'), 'lockstate' => (($item['allow_cid'] || $item['allow_gid'] || $item['deny_cid'] || $item['deny_gid']) ? 'lock' : 'unlock'),
'acl' => Libacl::populate($item, true, PermissionDescription::fromGlobalPermission('view_stream'), Libacl::get_post_aclDialogDescription(), 'acl_dialog_post'), 'acl' => Libacl::populate($item, true, PermissionDescription::fromGlobalPermission('view_stream'), Libacl::get_post_aclDialogDescription(), 'acl_dialog_post'),
'bang' => EMPTY_STR, 'bang' => EMPTY_STR,
@ -167,7 +167,9 @@ class Editpost extends Controller
'collections' => $collections, 'collections' => $collections,
'jotnets' => true, 'jotnets' => true,
'hide_expire' => true, 'hide_expire' => true,
'bbcode' => true 'bbcode' => true,
'checkin' => ($item['verb'] === 'Arrive'),
'checkout' => ($item['verb'] === 'Leave'),
]; ];
$editor = status_editor($x); $editor = status_editor($x);

View file

@ -94,7 +94,6 @@ class Filestorage extends Controller
public function get() public function get()
{ {
if (argc() > 1) { if (argc() > 1) {
$channel = Channel::from_username(argv(1)); $channel = Channel::from_username(argv(1));
} }

View file

@ -29,16 +29,39 @@ class Followers extends Controller
http_status_exit(404, 'Not found'); http_status_exit(404, 'Not found');
} }
$sigdata = HTTPSig::verify(EMPTY_STR);
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
$portable_id = $sigdata['portable_id'];
if (!check_channelallowed($portable_id)) {
http_status_exit(403, 'Permission denied');
}
if (!check_siteallowed($sigdata['signer'])) {
http_status_exit(403, 'Permission denied');
}
observer_auth($portable_id);
}
Libprofile::load(argv(1)); Libprofile::load(argv(1));
$observer_hash = get_observer_hash(); $observer_hash = get_observer_hash();
$sqlExtra = '';
if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'view_contacts')) { if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'view_contacts')) {
http_status_exit(403, 'Forbidden'); if ($observer_hash) {
$sqlExtra = " AND xchan_hash = '" . dbesc($observer_hash) . "' ";
}
else {
http_status_exit(403, 'Permission denied');
}
} }
$t = q( $t = q(
"select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 ", "select count(xchan_hash) as total from xchan
left join abconfig on abconfig.xchan = xchan_hash
left join abook on abook_xchan = xchan_hash
where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms'
and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0
and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 $sqlExtra ",
intval($channel['channel_id']), intval($channel['channel_id']),
intval($channel['channel_id']), intval($channel['channel_id']),
dbesc($channel['channel_hash']) dbesc($channel['channel_hash'])
@ -54,7 +77,12 @@ class Followers extends Controller
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
$r = q( $r = q(
"select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 $pager_sql", "select * from xchan left join abconfig on abconfig.xchan = xchan_hash
left join abook on abook_xchan = xchan_hash
where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system'
and abconfig.k = 'their_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s'
and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0
and abook_self = 0 $sqlExtra $pager_sql",
intval($channel['channel_id']), intval($channel['channel_id']),
intval($channel['channel_id']), intval($channel['channel_id']),
dbesc($channel['channel_hash']) dbesc($channel['channel_hash'])

View file

@ -29,16 +29,39 @@ class Following extends Controller
http_status_exit(404, 'Not found'); http_status_exit(404, 'Not found');
} }
$sigdata = HTTPSig::verify(EMPTY_STR);
if ($sigdata['portable_id'] && $sigdata['header_valid']) {
$portable_id = $sigdata['portable_id'];
if (!check_channelallowed($portable_id)) {
http_status_exit(403, 'Permission denied');
}
if (!check_siteallowed($sigdata['signer'])) {
http_status_exit(403, 'Permission denied');
}
observer_auth($portable_id);
}
Libprofile::load(argv(1)); Libprofile::load(argv(1));
$observer_hash = get_observer_hash(); $observer_hash = get_observer_hash();
$sqlExtra = '';
if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'view_contacts')) { if (!perm_is_allowed($channel['channel_id'], $observer_hash, 'view_contacts')) {
http_status_exit(403, 'Forbidden'); if ($observer_hash) {
$sqlExtra = " AND xchan_hash = '" . dbesc($observer_hash) . "' ";
}
else {
http_status_exit(403, 'Permission denied');
}
} }
$t = q( $t = q(
"select count(xchan_hash) as total from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0", "select count(xchan_hash) as total from xchan
left join abconfig on abconfig.xchan = xchan_hash
left join abook on abook_xchan = xchan_hash
where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms'
and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0
and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 $sqlExtra ",
intval($channel['channel_id']), intval($channel['channel_id']),
intval($channel['channel_id']), intval($channel['channel_id']),
dbesc($channel['channel_hash']) dbesc($channel['channel_hash'])
@ -55,7 +78,11 @@ class Following extends Controller
$pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start'])); $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval(App::$pager['itemspage']), intval(App::$pager['start']));
$r = q( $r = q(
"select * from xchan left join abconfig on abconfig.xchan = xchan_hash left join abook on abook_xchan = xchan_hash where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms' and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0 and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 $pager_sql", "select * from xchan left join abconfig on abconfig.xchan = xchan_hash
left join abook on abook_xchan = xchan_hash
where abook_channel = %d and abconfig.chan = %d and abconfig.cat = 'system' and abconfig.k = 'my_perms'
and abconfig.v like '%%send_stream%%' and xchan_hash != '%s' and xchan_orphan = 0
and xchan_deleted = 0 and abook_hidden = 0 and abook_pending = 0 and abook_self = 0 $sqlExtra $pager_sql",
intval($channel['channel_id']), intval($channel['channel_id']),
intval($channel['channel_id']), intval($channel['channel_id']),
dbesc($channel['channel_hash']) dbesc($channel['channel_hash'])

View file

@ -27,11 +27,7 @@ class Home extends Controller
Hook::call('home_init', $ret); Hook::call('home_init', $ret);
if (ActivityStreams::is_as_request()) { if (ActivityStreams::is_as_request()) {
$x = array_merge(['@context' => [ $x = array_merge(Activity::ap_context(), Activity::encode_site());
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
Activity::ap_schema()
]], Activity::encode_site());
$headers = []; $headers = [];
$headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"'; $headers['Content-Type'] = 'application/ld+json; profile="https://www.w3.org/ns/activitystreams"';

View file

@ -96,11 +96,7 @@ class Id extends Controller
http_status_exit(404, 'Not found'); http_status_exit(404, 'Not found');
} }
$x = array_merge(['@context' => [ $x = array_merge(Activity::ap_context(), $i);
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
Activity::ap_schema()
]], $i);
$headers = []; $headers = [];
$headers['Content-Type'] = 'application/x-nomad+json'; $headers['Content-Type'] = 'application/x-nomad+json';

View file

@ -163,10 +163,6 @@ class Impel extends Controller
$pagetitle = strtolower(URLify::transliterate($j['pagetitle'])); $pagetitle = strtolower(URLify::transliterate($j['pagetitle']));
} }
// Verify ability to use html or php!!!
$execflag = ((intval($channel['channel_id']) == intval(local_channel()) && ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false);
$i = q( $i = q(
"select id, edited, item_deleted from item where mid = '%s' and uid = %d limit 1", "select id, edited, item_deleted from item where mid = '%s' and uid = %d limit 1",
dbesc($arr['mid']), dbesc($arr['mid']),
@ -179,7 +175,7 @@ class Impel extends Controller
$arr['id'] = $i[0]['id']; $arr['id'] = $i[0]['id'];
// don't update if it has the same timestamp as the original // don't update if it has the same timestamp as the original
if ($arr['edited'] > $i[0]['edited']) { if ($arr['edited'] > $i[0]['edited']) {
$x = item_store_update($arr, $execflag); $x = item_store_update($arr);
} }
} else { } else {
if (($i) && (intval($i[0]['item_deleted']))) { if (($i) && (intval($i[0]['item_deleted']))) {
@ -190,7 +186,7 @@ class Impel extends Controller
intval(local_channel()) intval(local_channel())
); );
} else { } else {
$x = item_store($arr, $execflag); $x = item_store($arr);
} }
} }

View file

@ -180,8 +180,8 @@ class Import extends Controller
} }
$channel = import_channel($data['channel'], $account_id, $seize, $newname); $channel = import_channel($data['channel'], $account_id, $seize, $newname);
} else { }
$moving = false; else {
$channel = App::get_channel(); $channel = App::get_channel();
} }
@ -316,7 +316,7 @@ class Import extends Controller
if (is_array($data['hubloc'])) { if (is_array($data['hubloc'])) {
import_hublocs($channel, $data['hubloc'], $seize, $moving); import_hublocs($channel, $data['hubloc'], $seize);
} }
logger('import step 7'); logger('import step 7');

View file

@ -303,11 +303,7 @@ class Item extends Controller
if (!$i) { if (!$i) {
http_status_exit(404, 'Not found'); http_status_exit(404, 'Not found');
} }
$x = array_merge(['@context' => [ $x = array_merge(Activity::ap_context(), $i);
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
Activity::ap_schema()
]], $i);
$headers = []; $headers = [];
$headers['Content-Type'] = 'application/x-nomad+json'; $headers['Content-Type'] = 'application/x-nomad+json';
@ -491,6 +487,7 @@ class Item extends Controller
$plink = ((x($_REQUEST, 'permalink')) ? escape_tags($_REQUEST['permalink']) : ''); $plink = ((x($_REQUEST, 'permalink')) ? escape_tags($_REQUEST['permalink']) : '');
$obj_type = ((x($_REQUEST, 'obj_type')) ? escape_tags($_REQUEST['obj_type']) : ACTIVITY_OBJ_NOTE); $obj_type = ((x($_REQUEST, 'obj_type')) ? escape_tags($_REQUEST['obj_type']) : ACTIVITY_OBJ_NOTE);
$checkin = ((x($_REQUEST, 'checkin')) ? 1 : 0); $checkin = ((x($_REQUEST, 'checkin')) ? 1 : 0);
$checkout = ((x($_REQUEST, 'checkout')) ? 1 : 0);
$item_unpublished = ((isset($_REQUEST['draft'])) ? intval($_REQUEST['draft']) : 0); $item_unpublished = ((isset($_REQUEST['draft'])) ? intval($_REQUEST['draft']) : 0);
@ -882,9 +879,8 @@ class Item extends Controller
$body = ((isset($_REQUEST['body'])) ? trim($_REQUEST['body']) : EMPTY_STR); $body = ((isset($_REQUEST['body'])) ? trim($_REQUEST['body']) : EMPTY_STR);
$body .= ((isset($_REQUEST['attachment'])) ? trim($_REQUEST['attachment']) : EMPTY_STR); $body .= ((isset($_REQUEST['attachment'])) ? trim($_REQUEST['attachment']) : EMPTY_STR);
$postopts = ''; $postopts = '';
$haslocation = $lat || $lon;
$allow_empty = ((array_key_exists('allow_empty', $_REQUEST)) ? intval($_REQUEST['allow_empty']) : 0); $allow_empty = ((($checkin || $checkout) && $haslocation) || $_REQUEST['allow_empty']);
$private = ((isset($private) && $private) ? $private : intval($acl->is_private() || ($public_policy))); $private = ((isset($private) && $private) ? $private : intval($acl->is_private() || ($public_policy)));
// If this is a comment, set the permissions from the parent. // If this is a comment, set the permissions from the parent.
@ -931,13 +927,10 @@ class Item extends Controller
if (!$mimetype) { if (!$mimetype) {
$mimetype = 'text/x-multicode'; $mimetype = 'text/x-multicode';
} }
$execflag = ((intval($uid) == intval($profile_uid)
&& ($channel['channel_pageflags'] & PAGE_ALLOWCODE)) ? true : false);
if ($preview) { if ($preview) {
$summary = z_input_filter($summary, $mimetype, $execflag); $summary = z_input_filter($summary, $mimetype);
$body = z_input_filter($body, $mimetype, $execflag); $body = z_input_filter($body, $mimetype);
} }
@ -979,6 +972,9 @@ class Item extends Controller
if ($checkin) { if ($checkin) {
$verb = 'Arrive'; $verb = 'Arrive';
} }
if ($checkout) {
$verb = 'Leave';
}
if (in_array($mimetype, [ 'text/bbcode', 'text/x-multicode' ])) { if (in_array($mimetype, [ 'text/bbcode', 'text/x-multicode' ])) {
// BBCODE alert: the following functions assume bbcode input // BBCODE alert: the following functions assume bbcode input
@ -1182,7 +1178,13 @@ class Item extends Controller
} }
} }
if ($verb === 'Arrive') { $hook_args = ['location' => $location, 'latitude' => $lat, 'longitude' => $lon];
Hook::call('post_location', $hook_args);
$location = $hook_args['location'];
$lat = $hook_args['latitude'];
$lon = $hook_args['longitude'];
if (in_array($verb, ['Arrive', 'Leave'])) {
$body = preg_replace('/\[map=(.*?)\]/','', $body); $body = preg_replace('/\[map=(.*?)\]/','', $body);
$body = preg_replace('/\[map\](.*?)\[\/map\]/','', $body); $body = preg_replace('/\[map\](.*?)\[\/map\]/','', $body);
@ -1616,7 +1618,7 @@ class Item extends Controller
if ($orig_post) { if ($orig_post) {
$datarray['id'] = $post_id; $datarray['id'] = $post_id;
$x = item_store_update($datarray, $execflag); $x = item_store_update($datarray);
if ($x['success']) { if ($x['success']) {
Hook::call('after_item_store', $x['item']); Hook::call('after_item_store', $x['item']);
@ -1656,7 +1658,7 @@ class Item extends Controller
$post_id = 0; $post_id = 0;
} }
$post = item_store($datarray, $execflag); $post = item_store($datarray);
if ($post['success']) { if ($post['success']) {
Hook::call('after_item_store', $post['item']); Hook::call('after_item_store', $post['item']);
@ -2038,7 +2040,7 @@ class Item extends Controller
foreach ($answers as $answer) { foreach ($answers as $answer) {
if (trim($answer)) { if (trim($answer)) {
$ptr[] = ['name' => escape_tags($answer), 'type' => 'Note', 'replies' => ['type' => 'Collection', 'totalItems' => 0]]; $ptr[] = ['name' => escape_tags(trim($answer)), 'type' => 'Note', 'replies' => ['type' => 'Collection', 'totalItems' => 0]];
} }
} }

View file

@ -47,13 +47,12 @@ class Lists extends Controller
http_status_exit(403, 'Permission denied'); http_status_exit(403, 'Permission denied');
} }
observer_auth($portable_id); observer_auth($portable_id);
} elseif (Config::Get('system', 'require_authenticated_fetch', false)) { } elseif (Config::Get('system', 'require_authenticated_fetch')) {
http_status_exit(403, 'Permission denied'); http_status_exit(403, 'Permission denied');
} }
if (!perm_is_allowed($group['uid'], get_observer_hash(), 'view_contacts')) { $observer_hash = get_observer_hash();
http_status_exit(403, 'Permission denied'); $hasPermission = perm_is_allowed($group['uid'], $observer_hash, 'view_contacts');
}
$channel = Channel::from_id($group['uid']); $channel = Channel::from_id($group['uid']);
@ -61,13 +60,20 @@ class Lists extends Controller
http_status_exit(404, 'Not found'); http_status_exit(404, 'Not found');
} }
if (!$group['visible']) { $sqlExtra = '';
if ($channel['channel_hash'] !== get_observer_hash()) { if (!$group['visible'] || !$hasPermission) {
if ($observer_hash) {
if ($observer_hash !== $channel['channel_hash']) {
$sqlExtra = " AND xchan_hash = '" . dbesc(get_observer_hash()) . "' ";
}
}
else {
http_status_exit(403, 'Permission denied'); http_status_exit(403, 'Permission denied');
} }
} }
$total = AccessList::members($group['uid'], $group['id'], true);
$total = AccessList::members($group['uid'], $group['id'], true, sqlExtra: $sqlExtra);
if ($total) { if ($total) {
App::set_pager_total($total); App::set_pager_total($total);
App::set_pager_itemspage(100); App::set_pager_itemspage(100);
@ -75,14 +81,15 @@ class Lists extends Controller
if (App::$pager['unset'] && $total > 100) { if (App::$pager['unset'] && $total > 100) {
$ret = Activity::paged_collection_init($total, App::$query_string); $ret = Activity::paged_collection_init($total, App::$query_string);
$ret['name'] = $group['gname'];
$ret['attributedTo'] = Channel::url($channel);
} else { } else {
$members = AccessList::members($group['uid'], $group['id'], false, App::$pager['start'], App::$pager['itemspage']); $members = AccessList::members($group['uid'], $group['id'], false, App::$pager['start'],
App::$pager['itemspage'], sqlExtra: $sqlExtra);
$ret = Activity::encode_follow_collection($members, App::$query_string, 'OrderedCollection', $total); $ret = Activity::encode_follow_collection($members, App::$query_string, 'OrderedCollection', $total);
$ret['name'] = $group['gname'];
$ret['attributedTo'] = Channel::url($channel);
} }
if (! $sqlExtra) {
$ret['name'] = $group['gname'];
}
$ret['attributedTo'] = Channel::url($channel);
as_return_and_die($ret, $channel); as_return_and_die($ret, $channel);
} }
@ -157,7 +164,6 @@ class Lists extends Controller
goaway(z_root() . '/lists/' . argv(1) . '/' . argv(2)); goaway(z_root() . '/lists/' . argv(1) . '/' . argv(2));
} }
return;
} }
public function get() public function get()
@ -193,7 +199,7 @@ class Lists extends Controller
} }
$tpl = Theme::get_template('privacy_groups.tpl'); $tpl = Theme::get_template('privacy_groups.tpl');
$o = replace_macros($tpl, [ return replace_macros($tpl, [
'$title' => t('Access Lists'), '$title' => t('Access Lists'),
'$add_new_label' => t('Create access list'), '$add_new_label' => t('Create access list'),
'$new' => $new, '$new' => $new,
@ -209,8 +215,6 @@ class Lists extends Controller
'$count_label' => t('Members'), '$count_label' => t('Members'),
'$entries' => $entries '$entries' => $entries
]); ]);
return $o;
} }
$context = ['$submit' => t('Submit')]; $context = ['$submit' => t('Submit')];
@ -300,11 +304,10 @@ class Lists extends Controller
$members[] = micropro($member, true, 'mpgroup', 'card'); $members[] = micropro($member, true, 'mpgroup', 'card');
} }
} }
$o = replace_macros(Theme::get_template('listmembers.tpl'), [ return replace_macros(Theme::get_template('listmembers.tpl'), [
'$title' => t('List members'), '$title' => t('List members'),
'$members' => $members '$members' => $members
]); ]);
return $o;
} }
$members = AccessList::members(local_channel(), $group['id']); $members = AccessList::members(local_channel(), $group['id']);

View file

@ -5,7 +5,6 @@ namespace Code\Module;
use App; use App;
use Code\Web\Controller; use Code\Web\Controller;
use Code\Lib\Libsync; use Code\Lib\Libsync;
use Code\Lib\Channel;
use Code\Daemon\Run; use Code\Daemon\Run;
use Code\Access\PermissionRoles; use Code\Access\PermissionRoles;
@ -94,7 +93,7 @@ class Moderate extends Controller
$item['item_blocked'] = 0; $item['item_blocked'] = 0;
item_update_parent_commented($item); item_update_parent_commented($item);
// \Code\Lib\Activity::send_accept_activity(App::get_channel(),$item['author'], $item, $parent_item);
notice(t('Comment approved') . EOL); notice(t('Comment approved') . EOL);
} elseif ($action === 'drop') { } elseif ($action === 'drop') {
drop_item($post_id); drop_item($post_id);
@ -118,9 +117,9 @@ class Moderate extends Controller
// Announce activity so microblog destinations will see it in their home timeline // Announce activity so microblog destinations will see it in their home timeline
$role = get_pconfig(local_channel(), 'system', 'permissions_role'); $role = get_pconfig(local_channel(), 'system', 'permissions_role');
$rolesettings = PermissionRoles::role_perms($role); $rolesettings = PermissionRoles::role_perms($role);
$channel_type = isset($rolesettings['channel_type']) ? $rolesettings['channel_type'] : 'normal'; $channel_type = $rolesettings['channel_type'] ?? 'normal';
$is_group = (($channel_type === 'group') ? true : false); $is_group = $channel_type === 'group';
if ($is_group) { if ($is_group) {
tag_deliver(local_channel(), $post_id); tag_deliver(local_channel(), $post_id);
} }
@ -138,7 +137,7 @@ class Moderate extends Controller
$items = []; $items = [];
} }
$o = conversation($items, 'moderate', false, 'traditional'); $o = conversation($items, 'moderate', false);
$o .= alt_pager(count($items)); $o .= alt_pager(count($items));
return $o; return $o;
} }

View file

@ -60,6 +60,8 @@ class Ping extends Controller
$item_normal = item_normal(); $item_normal = item_normal();
$approvals = " AND NOT verb in ('Accept','Reject') ";
if (local_channel()) { if (local_channel()) {
$vnotify = get_pconfig(local_channel(), 'system', 'vnotify'); $vnotify = get_pconfig(local_channel(), 'system', 'vnotify');
$evdays = intval(get_pconfig(local_channel(), 'system', 'evdays')); $evdays = intval(get_pconfig(local_channel(), 'system', 'evdays'));
@ -169,6 +171,7 @@ class Ping extends Controller
WHERE uid = %d WHERE uid = %d
AND created > '%s' AND created > '%s'
$seenstr $seenstr
$approvals
$item_normal $item_normal
$sql_extra", $sql_extra",
intval($sys['channel_id']), intval($sys['channel_id']),
@ -195,6 +198,7 @@ class Ping extends Controller
AND author_xchan != '%s' AND author_xchan != '%s'
AND created > '%s' AND created > '%s'
$seenstr $seenstr
$approvals
$item_normal $item_normal
$sql_extra $sql_extra
ORDER BY created DESC ORDER BY created DESC
@ -207,7 +211,7 @@ class Ping extends Controller
if ($r) { if ($r) {
xchan_query($r); xchan_query($r);
foreach ($r as $rr) { foreach ($r as $rr) {
$rr['llink'] = str_replace('display/', 'pubstream/?f=&mid=', $rr['llink']); $rr['llink'] = str_replace('display/', 'pubstream/', $rr['llink']);
$z = Enotify::format($rr); $z = Enotify::format($rr);
if ($z) { if ($z) {
$local_result[] = $z; $local_result[] = $z;
@ -303,7 +307,7 @@ class Ping extends Controller
foreach ($t as $tt) { foreach ($t as $tt) {
$message = trim(strip_tags(bbcode($tt['msg']))); $message = trim(strip_tags(bbcode($tt['msg'])));
if (strpos($message, $tt['xname']) === 0) { if (str_starts_with($message, $tt['xname'])) {
$message = substr($message, strlen($tt['xname']) + 1); $message = substr($message, strlen($tt['xname']) + 1);
} }
@ -319,12 +323,12 @@ class Ping extends Controller
intval(local_channel()) intval(local_channel())
); );
$b64mid = ((strpos($r[0]['thr_parent'], 'b64.') === 0) ? $r[0]['thr_parent'] : gen_link_id($r[0]['thr_parent'])); $b64mid = ((str_starts_with($r[0]['thr_parent'], 'b64.')) ? $r[0]['thr_parent'] : gen_link_id($r[0]['thr_parent']));
} else { } else {
$b64mid = ((strpos($mid, 'b64.') === 0) ? $mid : gen_link_id($mid)); $b64mid = ((str_starts_with($mid, 'b64.')) ? $mid : gen_link_id($mid));
} }
$notifs[] = array( $notifs[] = [
'notify_link' => z_root() . '/notify/view/' . $tt['id'], 'notify_link' => z_root() . '/notify/view/' . $tt['id'],
'name' => $tt['xname'], 'name' => $tt['xname'],
'url' => $tt['url'], 'url' => $tt['url'],
@ -334,7 +338,7 @@ class Ping extends Controller
'b64mid' => (($tt['otype'] == 'item') ? $b64mid : 'undefined'), 'b64mid' => (($tt['otype'] == 'item') ? $b64mid : 'undefined'),
'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : 'undefined'), 'notify_id' => (($tt['otype'] == 'item') ? $tt['id'] : 'undefined'),
'message' => $message 'message' => $message
); ];
} }
} }
@ -353,6 +357,7 @@ class Ping extends Controller
AND author_xchan != '%s' AND author_xchan != '%s'
AND edited > '%s' AND edited > '%s'
$seenstr $seenstr
$approvals
$item_normal_moderate $item_normal_moderate
$sql_extra $sql_extra
ORDER BY created DESC ORDER BY created DESC
@ -390,6 +395,7 @@ class Ping extends Controller
AND author_xchan != '%s' AND author_xchan != '%s'
AND edited > '%s' AND edited > '%s'
$seenstr $seenstr
$approvals
$item_normal_moderate $item_normal_moderate
$sql_extra $sql_extra
ORDER BY created DESC ORDER BY created DESC
@ -448,7 +454,7 @@ class Ping extends Controller
); );
if ($r) { if ($r) {
foreach ($r as $rr) { foreach ($r as $rr) {
$result[] = array( $result[] = [
'notify_link' => z_root() . '/admin/accounts', 'notify_link' => z_root() . '/admin/accounts',
'name' => $rr['account_email'], 'name' => $rr['account_email'],
'addr' => $rr['account_email'], 'addr' => $rr['account_email'],
@ -457,7 +463,7 @@ class Ping extends Controller
'when' => relative_date($rr['account_created']), 'when' => relative_date($rr['account_created']),
'hclass' => ('notify-unseen'), 'hclass' => ('notify-unseen'),
'message' => t('requires approval') 'message' => t('requires approval')
); ];
} }
} }
@ -485,7 +491,7 @@ class Ping extends Controller
$today = ((substr($strt, 0, 10) === datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d')) ? true : false); $today = ((substr($strt, 0, 10) === datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d')) ? true : false);
$when = day_translate(datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart'], $bd_format)) . (($today) ? ' ' . t('[today]') : ''); $when = day_translate(datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['dtstart'], $bd_format)) . (($today) ? ' ' . t('[today]') : '');
$result[] = array( $result[] = [
'notify_link' => z_root() . '/events', /// @FIXME this takes you to an edit page and it may not be yours, we really want to just view the single event --> '/events/event/' . $rr['event_hash'], 'notify_link' => z_root() . '/events', /// @FIXME this takes you to an edit page and it may not be yours, we really want to just view the single event --> '/events/event/' . $rr['event_hash'],
'name' => $rr['xchan_name'], 'name' => $rr['xchan_name'],
'addr' => $rr['xchan_addr'], 'addr' => $rr['xchan_addr'],
@ -494,7 +500,7 @@ class Ping extends Controller
'when' => $when, 'when' => $when,
'hclass' => ('notify-unseen'), 'hclass' => ('notify-unseen'),
'message' => t('posted an event') 'message' => t('posted an event')
); ];
} }
} }
@ -519,7 +525,7 @@ class Ping extends Controller
); );
if ($r) { if ($r) {
foreach ($r as $rr) { foreach ($r as $rr) {
$result[] = array( $result[] = [
'notify_link' => z_root() . '/sharedwithme', 'notify_link' => z_root() . '/sharedwithme',
'name' => $rr['xchan_name'], 'name' => $rr['xchan_name'],
'addr' => $rr['xchan_addr'], 'addr' => $rr['xchan_addr'],
@ -528,7 +534,7 @@ class Ping extends Controller
'when' => relative_date($rr['created']), 'when' => relative_date($rr['created']),
'hclass' => ('notify-unseen'), 'hclass' => ('notify-unseen'),
'message' => t('shared a file with you') 'message' => t('shared a file with you')
); ];
} }
} }
@ -604,6 +610,7 @@ class Ping extends Controller
"SELECT id, author_xchan FROM item "SELECT id, author_xchan FROM item
WHERE uid = %d and edited > '%s' WHERE uid = %d and edited > '%s'
$seenstr $seenstr
$approvals
$item_normal $item_normal
$sql_extra ", $sql_extra ",
intval(local_channel()), intval(local_channel()),
@ -611,7 +618,7 @@ class Ping extends Controller
); );
if ($r) { if ($r) {
$arr = array('items' => $r); $arr = ['items' => $r];
Hook::call('network_ping', $arr); Hook::call('network_ping', $arr);
foreach ($r as $it) { foreach ($r as $it) {
@ -632,7 +639,8 @@ class Ping extends Controller
$r = q( $r = q(
"SELECT id, author_xchan FROM item "SELECT id, author_xchan FROM item
WHERE item_wall = 1 and uid = %d and edited > '%s' WHERE item_wall = 1 and uid = %d and edited > '%s'
$seenstr $seenstr
$approvals
$item_normal $item_normal
$sql_extra ", $sql_extra ",
intval(local_channel()), intval(local_channel()),
@ -739,7 +747,7 @@ class Ping extends Controller
$result['birthdays'] = 0; $result['birthdays'] = 0;
} }
/*
if ($vnotify & VNOTIFY_FORUMS) { if ($vnotify & VNOTIFY_FORUMS) {
$forums = get_forum_channels(local_channel()); $forums = get_forum_channels(local_channel());
@ -788,7 +796,7 @@ class Ping extends Controller
$result['forums_sub'] = $forums; $result['forums_sub'] = $forums;
} }
} }
*/
// Mark all of the stream notifications seen if all three of them are caught up. // Mark all of the stream notifications seen if all three of them are caught up.
// This also resets the pconfig storage for items_seen // This also resets the pconfig storage for items_seen

View file

@ -350,11 +350,7 @@ class Search extends Controller
$i = Activity::encode_item_collection($items, 'search?' . $saved_id , 'OrderedCollection', true, count($items)); $i = Activity::encode_item_collection($items, 'search?' . $saved_id , 'OrderedCollection', true, count($items));
$x = array_merge(['@context' => [ $x = array_merge(Activity::ap_context(), $i);
ACTIVITYSTREAMS_JSONLD_REV,
'https://w3id.org/security/v1',
Activity::ap_schema()
]], $i);
$headers = []; $headers = [];
$headers['Content-Type'] = 'application/x-nomad+json'; $headers['Content-Type'] = 'application/x-nomad+json';

View file

@ -62,7 +62,7 @@ class Channel
PermissionLimits::Set(local_channel(), 'view_contacts', $view_contacts); PermissionLimits::Set(local_channel(), 'view_contacts', $view_contacts);
$this->publish = (((x($_POST, 'profile_in_directory')) && (intval($_POST['profile_in_directory']) == 1)) ? 1 : 0); $this->publish = (((x($_POST, 'profile_in_directory')) && (intval($_POST['profile_in_directory']) == 1)) ? 1 : 0);
$username = ((x($_POST, 'username')) ? escape_tags(trim($_POST['username'])) : ''); $channel_name = ((x($_POST, 'channel_name')) ? escape_tags(trim($_POST['channel_name'])) : '');
$timezone = ((x($_POST, 'timezone_select')) ? notags(trim($_POST['timezone_select'])) : ''); $timezone = ((x($_POST, 'timezone_select')) ? notags(trim($_POST['timezone_select'])) : '');
$defloc = ((x($_POST, 'defloc')) ? notags(trim($_POST['defloc'])) : ''); $defloc = ((x($_POST, 'defloc')) ? notags(trim($_POST['defloc'])) : '');
$maxreq = ((x($_POST, 'maxreq')) ? intval($_POST['maxreq']) : 0); $maxreq = ((x($_POST, 'maxreq')) ? intval($_POST['maxreq']) : 0);
@ -137,9 +137,9 @@ class Channel
$name_change = false; $name_change = false;
if ($username != $channel['channel_name']) { if ($channel_name != $channel['channel_name']) {
$name_change = true; $name_change = true;
$err = Zlib\Channel::validate_channelname($username); $err = Zlib\Channel::validate_channelname($channel_name);
if ($err) { if ($err) {
notice($err); notice($err);
return; return;
@ -177,7 +177,7 @@ class Channel
$r = q( $r = q(
"update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', "update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s',
channel_notifyflags = %d, channel_max_friend_req = %d, channel_expire_days = %d where channel_id = %d", channel_notifyflags = %d, channel_max_friend_req = %d, channel_expire_days = %d where channel_id = %d",
dbesc($username), dbesc($channel_name),
intval($pageflags), intval($pageflags),
dbesc($timezone), dbesc($timezone),
dbesc($defloc), dbesc($defloc),
@ -206,17 +206,17 @@ class Channel
// catch xchans for all protocols by matching the url // catch xchans for all protocols by matching the url
$r = q( $r = q(
"update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_url = '%s'", "update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_url = '%s'",
dbesc($username), dbesc($channel_name),
dbesc(datetime_convert()), dbesc(datetime_convert()),
dbesc(z_root() . '/channel/' . $channel['channel_address']) dbesc(z_root() . '/channel/' . $channel['channel_address'])
); );
$r = q( $r = q(
"update profile set fullname = '%s' where uid = %d and is_default = 1", "update profile set fullname = '%s' where uid = %d and is_default = 1",
dbesc($username), dbesc($channel_name),
intval($channel['channel_id']) intval($channel['channel_id'])
); );
if (Zlib\Channel::is_system($channel['channel_id'])) { if (Zlib\Channel::is_system($channel['channel_id'])) {
set_config('system', 'sitename', $username); set_config('system', 'sitename', $channel_name);
} }
} }
@ -280,7 +280,7 @@ class Channel
// logger('permiss: ' . print_r($permiss,true)); // logger('permiss: ' . print_r($permiss,true));
$username = $channel['channel_name']; $channel_name = $channel['channel_name'];
$nickname = $channel['channel_address']; $nickname = $channel['channel_address'];
$timezone = $channel['channel_timezone']; $timezone = $channel['channel_timezone'];
$notify = $channel['channel_notifyflags']; $notify = $channel['channel_notifyflags'];
@ -433,7 +433,7 @@ class Channel
'$form_security_token' => get_form_security_token("settings"), '$form_security_token' => get_form_security_token("settings"),
'$nickname_block' => $prof_addr, '$nickname_block' => $prof_addr,
'$h_basic' => t('Basic Settings'), '$h_basic' => t('Basic Settings'),
'$username' => ['username', t('Full name'), $username, ''], '$channel_name' => ['channel_name', t('Full name'), $channel_name, ''],
'$timezone' => ['timezone_select', t('Your timezone'), $timezone, t('This is important for showing the correct time on shared events'), get_timezones()], '$timezone' => ['timezone_select', t('Your timezone'), $timezone, t('This is important for showing the correct time on shared events'), get_timezones()],
'$defloc' => ['defloc', t('Default post location'), $defloc, t('Optional geographical location to display on your posts')], '$defloc' => ['defloc', t('Default post location'), $defloc, t('Optional geographical location to display on your posts')],
'$allowloc' => ['allow_location', t('Obtain post location from your web browser or device'), ((get_pconfig(local_channel(), 'system', 'use_browser_location')) ? 1 : ''), '', $yes_no], '$allowloc' => ['allow_location', t('Obtain post location from your web browser or device'), ((get_pconfig(local_channel(), 'system', 'use_browser_location')) ? 1 : ''), '', $yes_no],

View file

@ -4,7 +4,7 @@ namespace Code\Module;
use App; use App;
use Code\Web\Controller; use Code\Web\Controller;
use Code\Lib\Apps; use Code\Lib\Activity;
use Code\Lib\Libsync; use Code\Lib\Libsync;
use Code\Lib\LibBlock; use Code\Lib\LibBlock;
use Code\Lib\Libzot; use Code\Lib\Libzot;
@ -17,92 +17,66 @@ class Superblock extends Controller
public function init() public function init()
{ {
$handled = false;
if (!local_channel()) { if (!local_channel()) {
return; return;
} }
$inline = (isset($_REQUEST['manual_block']) ? true : false); $inline = isset($_REQUEST['manual_block']);
$reason = (!empty($_REQUEST['reason'])) ? escape_tags($_REQUEST['reason']) : '';
$type = BLOCKTYPE_CHANNEL; $type = BLOCKTYPE_CHANNEL;
$blocked = trim($_REQUEST['block']); $blocked = trim($_REQUEST['block']);
if (!$blocked) {
$blocked = trim($_REQUEST['blocksite']);
if ($blocked) {
$type = BLOCKTYPE_SERVER;
}
}
$m = parse_url($blocked);
if ($m['scheme'] && $m['host'] && (($type === BLOCKTYPE_SERVER) || (!$m['path']))) {
if (strcasecmp($m['host'], App::get_hostname()) === 0) {
notice(t('Blocking this site is not permitted.'));
if ($inline) {
return;
}
killme();
}
$type = BLOCKTYPE_SERVER;
$blocked = $m['host'];
}
$handled = false;
$ignored = [];
if ($blocked) { if ($blocked) {
$handled = true; $handled = true;
if ($type === BLOCKTYPE_CHANNEL) { $r = q(
$r = q( "select * from xchan where ( xchan_hash = '%s' or xchan_addr = '%s' or xchan_url = '%s' )",
"select * from xchan where ( xchan_hash = '%s' or xchan_addr = '%s' or xchan_url = '%s' )", dbesc($blocked),
dbesc($blocked), dbesc($blocked),
dbesc($blocked), dbesc($blocked)
dbesc($blocked) );
);
if (!$r) { if (!$r) {
// not in cache - try discovery // not in cache - try discovery
$wf = discover_resource($blocked, '', false); $wf = discover_resource($blocked, '', false);
if (!$wf) { if (!$wf) {
notice(t('Channel not found.') . EOL); notice(t('Channel not found.') . EOL);
if ($inline) { if ($inline) {
return; return;
}
killme();
}
if ($wf) {
// something was discovered - find the record which was just created.
$r = q(
"select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' )",
dbesc(($wf) ? $wf : $blocked),
dbesc($blocked),
dbesc($blocked)
);
} }
killme();
} }
if ($r) { if ($wf) {
$r = Libzot::zot_record_preferred($r, 'xchan_network'); // something was discovered - find the record which was just created.
$blocked = $r['xchan_hash'];
$r = q(
"select * from xchan where ( xchan_hash = '%s' or xchan_url = '%s' or xchan_addr = '%s' )",
dbesc($wf),
dbesc($blocked),
dbesc($blocked)
);
} }
} }
$bl = [ if ($r) {
'block_channel_id' => local_channel(), $r = Libzot::zot_record_preferred($r, 'xchan_network');
'block_entity' => $blocked, $blocked = $r['xchan_hash'];
'block_type' => $type,
'block_comment' => t('Added by Superblock')
];
LibBlock::store($bl); $bl = [
'block_channel_id' => local_channel(),
'block_entity' => $blocked,
'block_type' => $type,
'block_comment' => t('Added by Superblock')
];
$sync = []; LibBlock::store($bl);
$sync = [];
$sync['block'] = [LibBlock::fetch_by_entity(local_channel(), $blocked)];
$sync['block_xchan'] = [$r];
$sync['block'] = [LibBlock::fetch_by_entity(local_channel(), $blocked)];
$sync['block_xchan'] = [$r];
if ($type === BLOCKTYPE_CHANNEL) {
$z = q( $z = q(
"insert into xign ( uid, xchan ) values ( %d , '%s' ) ", "insert into xign ( uid, xchan ) values ( %d , '%s' ) ",
intval(local_channel()), intval(local_channel()),
@ -140,31 +114,23 @@ class Superblock extends Controller
$sync['xign'] = [['uid' => local_channel(), 'xchan' => $_GET['block']]]; $sync['xign'] = [['uid' => local_channel(), 'xchan' => $_GET['block']]];
} }
Libsync::build_sync_packet(0, $sync); Libsync::build_sync_packet(0, $sync);
} } else {
$unblocked = trim($_REQUEST['unblock']);
$type = BLOCKTYPE_CHANNEL;
$unblocked = trim($_REQUEST['unblock']);
if (!$unblocked) {
$unblocked = trim($_REQUEST['unblocksite']);
if ($unblocked) { if ($unblocked) {
$type = BLOCKTYPE_SERVER; $handled = true;
} if (check_form_security_token('superblock', 'sectok')) {
} $r = LibBlock::fetch_by_entity(local_channel(), $unblocked);
if ($unblocked) { if ($r) {
$handled = true; LibBlock::remove(local_channel(), $unblocked);
if (check_form_security_token('superblock', 'sectok')) {
$r = LibBlock::fetch_by_entity(local_channel(), $unblocked); $sync = [];
if ($r) { $sync['block'] = [[
LibBlock::remove(local_channel(), $unblocked); 'block_channel_id' => local_channel(),
'block_entity' => $unblocked,
'block_type' => $type,
'deleted' => true,
]];
$sync = [];
$sync['block'] = [[
'block_channel_id' => local_channel(),
'block_entity' => $unblocked,
'block_type' => $type,
'deleted' => true,
]];
if ($type === BLOCKTYPE_CHANNEL) {
$ab = q( $ab = q(
"select * from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_xchan = '%s'", "select * from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and abook_xchan = '%s'",
intval(local_channel()), intval(local_channel()),
@ -192,7 +158,65 @@ class Superblock extends Controller
intval(local_channel()), intval(local_channel()),
dbesc($unblocked) dbesc($unblocked)
); );
Libsync::build_sync_packet(0, $sync);
} }
else {
return;
}
}
}
}
$type = BLOCKTYPE_SERVER;
$blocked = trim($_REQUEST['blocksite']);
if ($blocked) {
$handled = true;
$servers = Activity::get_actor_hublocs($blocked);
if ($servers) {
foreach ($servers as $server) {
$m = parse_url($server['hubloc_url']);
if ($m['scheme'] && $m['host']) {
if (strcasecmp($m['host'], App::get_hostname()) === 0) {
notice(t('Blocking this site is not permitted.'));
if ($inline) {
return;
}
killme();
}
$blocked = $m['host'];
$bl = [
'block_channel_id' => local_channel(),
'block_entity' => $blocked,
'block_type' => $type,
'block_comment' => t('Added by Superblock')
];
LibBlock::store($bl);
$sync = [];
$sync['block'] = [LibBlock::fetch_by_entity(local_channel(), $blocked)];
Libsync::build_sync_packet(0, $sync);
}
}
}
}
$unblocked = trim($_REQUEST['unblocksite']);
if ($unblocked) {
$handled = true;
if (check_form_security_token('superblock', 'sectok')) {
$r = LibBlock::fetch_by_entity(local_channel(), $unblocked);
if ($r) {
LibBlock::remove(local_channel(), $unblocked);
$sync = [];
$sync['block'] = [[
'block_channel_id' => local_channel(),
'block_entity' => $unblocked,
'block_type' => $type,
'deleted' => true,
]];
Libsync::build_sync_packet(0, $sync); Libsync::build_sync_packet(0, $sync);
} }
} }
@ -204,9 +228,9 @@ class Superblock extends Controller
if ($unblocked || $inline) { if ($unblocked || $inline) {
return; return;
} }
killme(); killme();
} }
} }
public function get() public function get()
@ -255,7 +279,7 @@ class Superblock extends Controller
]); ]);
return replace_macros(Theme::get_template('generic_app_settings.tpl'), [ return replace_macros(Theme::get_template('generic_app_settings.tpl'), [
'$addon' => array('superblock', t('Manage Blocks'), '', t('Submit')), '$addon' => ['superblock', t('Manage Blocks'), '', t('Submit')],
'$content' => $sc '$content' => $sc
]); ]);
} }

View file

@ -9,6 +9,7 @@ use Code\Identity\OAuth2Server;
use Code\Identity\OAuth2Storage; use Code\Identity\OAuth2Storage;
use OAuth2\Request; use OAuth2\Request;
use OAuth2\Response; use OAuth2\Response;
use OAuth2\GrantType;
class Token extends Controller class Token extends Controller
{ {
@ -38,9 +39,13 @@ class Token extends Controller
} }
$storage = new OAuth2Storage(DBA::$dba->db); $storage = new OAuth2Storage(DBA::$dba->db);
$s = new OAuth2Server($storage); $server = new OAuth2Server($storage);
// Add the "Client Credentials" grant type (it is the simplest of the grant types)
$server->addGrantType(new GrantType\ClientCredentials($storage));
// Add the "Authorization Code" grant type (this is where the oauth magic happens)
$server->addGrantType(new GrantType\AuthorizationCode($storage));
$request = Request::createFromGlobals(); $request = Request::createFromGlobals();
$response = $s->handleTokenRequest($request); $response = $server->handleTokenRequest($request);
$response->send(); $response->send();
killme(); killme();
} }

View file

@ -27,7 +27,7 @@ class Vote extends Controller
$fetch = null; $fetch = null;
$id = argv(1); $id = argv(1);
$response = $_REQUEST['answer']; $response = trim($_REQUEST['answer']);
if ($id) { if ($id) {
$fetch = q( $fetch = q(
@ -47,9 +47,9 @@ class Vote extends Controller
if ($obj['oneOf']) { if ($obj['oneOf']) {
foreach ($obj['oneOf'] as $selection) { foreach ($obj['oneOf'] as $selection) {
// logger('selection: ' . $selection); // logger('selection: ' . '"' . $selection['name'] . '"');
// logger('response: ' . $response); // logger('response: ' . '"' . $response . '"');
if ($selection['name'] && $selection['name'] === $response) { if ($selection['name'] && trim($selection['name']) === $response) {
$valid = true; $valid = true;
} }
} }
@ -58,7 +58,7 @@ class Vote extends Controller
$choices = []; $choices = [];
if ($obj['anyOf']) { if ($obj['anyOf']) {
foreach ($obj['anyOf'] as $selection) { foreach ($obj['anyOf'] as $selection) {
$choices[] = $selection['name']; $choices[] = trim($selection['name']);
} }
foreach ($response as $res) { foreach ($response as $res) {
if (!in_array($res, $choices)) { if (!in_array($res, $choices)) {

View file

@ -140,7 +140,7 @@ class NomadHandler implements IHandler
// if ! $update create a linked identity // if ! $update create a linked identity
xchan_change_key($xchan, $newxchan, $data); xchan_change_key($xchan, $newxchan);
$ret['success'] = true; $ret['success'] = true;
return $ret; return $ret;

View file

@ -227,27 +227,27 @@ class Theme
} }
} }
public static function get_template($s, $root = '') public static function get_template($filename, $root = '')
{ {
$testroot = ($root=='') ? $testroot = "ROOT" : $root; $testroot = ($root=='') ? $testroot = "ROOT" : $root;
$t = App::template_engine(); $t = App::template_engine();
if (isset(App::$override_markup_templates[$testroot][$s]["content"])) { if (isset(App::$override_markup_templates[$testroot][$filename]["content"])) {
return App::$override_markup_templates[$testroot][$s]["content"]; return App::$override_markup_templates[$testroot][$filename]["content"];
} else { } else {
if (isset(App::$override_markup_templates[$testroot][$s]["root"]) && if (isset(App::$override_markup_templates[$testroot][$filename]["root"]) &&
isset(App::$override_markup_templates[$testroot][$s]["file"])) { isset(App::$override_markup_templates[$testroot][$filename]["file"])) {
$s = App::$override_markup_templates[$testroot][$s]["file"]; $filename = App::$override_markup_templates[$testroot][$filename]["file"];
$root = App::$override_markup_templates[$testroot][$s]["root"]; $root = App::$override_markup_templates[$testroot][$filename]["root"];
} elseif (App::$override_templateroot) { } elseif (App::$override_templateroot) {
$newroot = App::$override_templateroot.$root; $newroot = App::$override_templateroot.$root;
if ($newroot != '' && !str_ends_with($newroot, '/')) { if ($newroot != '' && !str_ends_with($newroot, '/')) {
$newroot .= '/'; $newroot .= '/';
} }
$template = $t->get_template($s, $newroot); $template = $t->get_template($filename, $newroot);
} }
$template = $t->get_template($s, $root); $template = $t->get_template($filename, $root);
return $template; return $template;
} }
} }

View file

@ -63,7 +63,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
$this->ext_path = $ext_path; $this->ext_path = $ext_path;
// remove "/cloud" from the beginning of the path // remove "/cloud" from the beginning of the path
$modulename = App::$module; $modulename = App::$module;
$this->red_path = ((strpos($ext_path, '/' . $modulename) === 0) ? substr($ext_path, strlen($modulename) + 1) : $ext_path); $this->red_path = ((str_starts_with($ext_path, '/' . $modulename)) ? substr($ext_path, strlen($modulename) + 1) : $ext_path);
if (!$this->red_path) { if (!$this->red_path) {
$this->red_path = '/'; $this->red_path = '/';
} }
@ -71,9 +71,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
$this->folder_hash = ''; $this->folder_hash = '';
$this->getDir(); $this->getDir();
if ($this->auth->browser) { $this->auth->browser?->set_writeable();
$this->auth->browser->set_writeable();
}
} }
private function log() private function log()
@ -184,7 +182,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
if ($ch) { if ($ch) {
$sync = attach_export_data($ch, $this->folder_hash); $sync = attach_export_data($ch, $this->folder_hash);
if ($sync) { if ($sync) {
Libsync::build_sync_packet($ch['channel_id'], array('file' => array($sync))); Libsync::build_sync_packet($ch['channel_id'], ['file' => [$sync]]);
} }
} }
@ -390,7 +388,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
$sync = attach_export_data($channel, $hash); $sync = attach_export_data($channel, $hash);
if ($sync) { if ($sync) {
Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
} }
} }
@ -416,14 +414,14 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
// folder already exists. // folder already exists.
require_once('include/attach.php'); require_once('include/attach.php');
$result = attach_mkdir($channel, $this->auth->observer, array('filename' => $name, 'folder' => $this->folder_hash, 'force' => true)); $result = attach_mkdir($channel, $this->auth->observer, ['filename' => $name, 'folder' => $this->folder_hash, 'force' => true]);
if ($result['success']) { if ($result['success']) {
$sync = attach_export_data($channel, $result['data']['hash']); $sync = attach_export_data($channel, $result['data']['hash']);
logger('createDirectory: attach_export_data returns $sync:' . print_r($sync, true), LOGGER_DEBUG); logger('createDirectory: attach_export_data returns $sync:' . print_r($sync, true), LOGGER_DEBUG);
if ($sync) { if ($sync) {
Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
} }
} else { } else {
logger('error ' . print_r($result, true), LOGGER_DEBUG); logger('error ' . print_r($result, true), LOGGER_DEBUG);
@ -452,10 +450,10 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
$channel = Channel::from_id($this->auth->owner_id); $channel = Channel::from_id($this->auth->owner_id);
if ($channel) { if ($channel) {
$sync = attach_export_data($channel, $this->folder_hash, true); $sync = attach_export_data($channel, $this->folder_hash, true);
if ($sync) { if ($sync) {
Libsync::build_sync_packet($channel['channel_id'], array('file' => array($sync))); Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
} }
} }
} }
@ -497,7 +495,17 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
return false; return false;
} }
return attach_move($this->auth->owner_id, $sourceNode->data['hash'], $this->folder_hash); $result = attach_move($this->auth->owner_id, $sourceNode->data['hash'], $this->folder_hash);
if ($result) {
$channel = Channel::from_id($this->auth->owner_id);
if ($channel) {
$sync = attach_export_data($channel, $sourceNode->data['hash'], false);
if ($sync) {
Libsync::build_sync_packet($channel['channel_id'], ['file' => [$sync]]);
}
}
}
return $result;
} }
@ -710,7 +718,7 @@ class Directory extends DAV\Node implements DAV\ICollection, DAV\IQuota, DAV\IMo
); );
foreach ($r as $rr) { foreach ($r as $rr) {
if (App::$module === 'cloud' && (strpos($rr['filename'], '.') === 0) && (!get_pconfig($channel_id, 'system', 'show_dot_files'))) { if (App::$module === 'cloud' && (str_starts_with($rr['filename'], '.')) && (!get_pconfig($channel_id, 'system', 'show_dot_files'))) {
continue; continue;
} }

View file

@ -54,10 +54,10 @@ class File extends DAV\Node implements DAV\IFile {
* *
* @param string $name * @param string $name
* @param array $data from attach table * @param array $data from attach table
* @param &$auth * @param $auth
*/ */
public function __construct($name, $data, &$auth) { public function __construct($name, $data, $auth) {
$this->name = $name; $this->name = $name;
$this->data = $data; $this->data = $data;
$this->auth = $auth; $this->auth = $auth;
@ -89,6 +89,8 @@ class File extends DAV\Node implements DAV\IFile {
throw new DAV\Exception\Forbidden('Permission denied.'); throw new DAV\Exception\Forbidden('Permission denied.');
} }
// attach_move($channel_id, $resource_id, $new_folder_hash, $newname = '')
$newName = str_replace('/', '%2F', $newName); $newName = str_replace('/', '%2F', $newName);
$r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND id = %d", $r = q("UPDATE attach SET filename = '%s' WHERE hash = '%s' AND id = %d",
@ -99,7 +101,7 @@ class File extends DAV\Node implements DAV\IFile {
$x = attach_syspaths($this->auth->owner_id,$this->data['hash']); $x = attach_syspaths($this->auth->owner_id,$this->data['hash']);
$y = q("update attach set display_path = '%s where hash = '%s' and uid = %d", $y = q("update attach set display_path = '%s' where hash = '%s' and uid = %d",
dbesc($x['path']), dbesc($x['path']),
dbesc($this->data['hash']), dbesc($this->data['hash']),
intval($this->auth->owner_id) intval($this->auth->owner_id)

View file

@ -30,8 +30,12 @@ Class Stdio {
if ($in && $out) { if ($in && $out) {
$size = self::pipe_streams($in, $out, $bufsize); $size = self::pipe_streams($in, $out, $bufsize);
} }
fclose($in); if ($in) {
fclose($out); fclose($in);
}
if ($out) {
fclose($out);
}
restore_error_handler(); restore_error_handler();
return $size; return $size;
} }

33
Code/Update/_1264.php Normal file
View file

@ -0,0 +1,33 @@
<?php
namespace Code\Update;
class _1264
{
public function run()
{
q("START TRANSACTION");
if (ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
$r = q("ALTER TABLE item ADD approved text NOT NULL DEFAULT ''");
} else {
$r = q("ALTER TABLE item ADD approved varchar(255) NOT NULL DEFAULT ''");
}
if ($r) {
q("COMMIT");
return UPDATE_SUCCESS;
}
q("ROLLBACK");
return UPDATE_FAILED;
}
public function verify()
{
$columns = db_columns('item');
return in_array('approved', $columns);
}
}

View file

@ -146,7 +146,7 @@ class Notifications implements WidgetInterface
]; ];
} }
$o = replace_macros(Theme::get_template('notifications_widget.tpl'), [ return replace_macros(Theme::get_template('notifications_widget.tpl'), [
'$module' => App::$module, '$module' => App::$module,
'$notifications' => $notifications, '$notifications' => $notifications,
'$notifications_label' => t('Notifications'), '$notifications_label' => t('Notifications'),
@ -155,6 +155,5 @@ class Notifications implements WidgetInterface
'$startpage' => get_pconfig(local_channel(), 'system', 'startpage') '$startpage' => get_pconfig(local_channel(), 'system', 'startpage')
]); ]);
return $o;
} }
} }

View file

@ -52,23 +52,20 @@ class Savedsearch implements WidgetInterface
$srchurl = App::$query_string; $srchurl = App::$query_string;
$srchurl = rtrim(preg_replace('/searchsave\=[^\&].*?(\&|$)/is', '', $srchurl), '&'); $srchurl = rtrim(preg_replace('/searchsave\=[^\&].*?(\&|$)/is', '', $srchurl), '&');
$hasq = ((strpos($srchurl, '?') !== false) ? true : false);
$srchurl = rtrim(preg_replace('/searchremove\=[^\&].*?(\&|$)/is', '', $srchurl), '&'); $srchurl = rtrim(preg_replace('/searchremove\=[^\&].*?(\&|$)/is', '', $srchurl), '&');
$srchurl = rtrim(preg_replace('/search\=[^\&].*?(\&|$)/is', '', $srchurl), '&'); $srchurl = rtrim(preg_replace('/search\=[^\&].*?(\&|$)/is', '', $srchurl), '&');
$srchurl = rtrim(preg_replace('/submit\=[^\&].*?(\&|$)/is', '', $srchurl), '&'); $srchurl = rtrim(preg_replace('/submit\=[^\&].*?(\&|$)/is', '', $srchurl), '&');
$srchurl = str_replace(array('?f=', '&f='), array('', ''), $srchurl); $srchurl = str_replace(['?f=', '&f='], ['', ''], $srchurl);
$hasq = ((strpos($srchurl, '?') !== false) ? true : false); $hasq = str_contains($srchurl, '?');
$hasamp = ((strpos($srchurl, '&') !== false) ? true : false); $hasamp = str_contains($srchurl, '&');
if (($hasamp) && (!$hasq)) { if (($hasamp) && (!$hasq)) {
$srchurl = substr($srchurl, 0, strpos($srchurl, '&')) . '?f=&' . substr($srchurl, strpos($srchurl, '&') + 1); $srchurl = substr($srchurl, 0, strpos($srchurl, '&')) . '?f=&' . substr($srchurl, strpos($srchurl, '&') + 1);
} }
$o = '';
$r = q( $r = q(
"select tid,term from term WHERE uid = %d and ttype = %d ", "select tid,term from term WHERE uid = %d and ttype = %d ",
intval(local_channel()), intval(local_channel()),
@ -79,7 +76,7 @@ class Savedsearch implements WidgetInterface
if (count($r)) { if (count($r)) {
foreach ($r as $rr) { foreach ($r as $rr) {
$saved[] = array( $saved[] = [
'id' => $rr['tid'], 'id' => $rr['tid'],
'term' => $rr['term'], 'term' => $rr['term'],
'dellink' => z_root() . '/' . $srchurl . (($hasq || $hasamp) ? '' : '?f=') . '&amp;searchremove=1&amp;search=' . urlencode($rr['term']), 'dellink' => z_root() . '/' . $srchurl . (($hasq || $hasamp) ? '' : '?f=') . '&amp;searchremove=1&amp;search=' . urlencode($rr['term']),
@ -88,18 +85,17 @@ class Savedsearch implements WidgetInterface
'encodedterm' => urlencode($rr['term']), 'encodedterm' => urlencode($rr['term']),
'delete' => t('Remove term'), 'delete' => t('Remove term'),
'selected' => ($search == $rr['term']), 'selected' => ($search == $rr['term']),
); ];
} }
} }
$tpl = Theme::get_template("saved_searches.tpl"); $tpl = Theme::get_template("saved_searches.tpl");
$o = replace_macros($tpl, array( return replace_macros($tpl, [
'$title' => t('Saved Searches'), '$title' => t('Saved Searches'),
'$add' => t('add'), '$add' => t('add'),
'$searchbox' => searchbox($search, 'netsearch-box', $srchurl . (($hasq) ? '' : '?f='), true), '$searchbox' => searchbox($search, 'netsearch-box', $srchurl . (($hasq) ? '' : '?f='), true),
'$saved' => $saved, '$saved' => $saved,
)); ]);
return $o;
} }
} }

View file

@ -2,7 +2,6 @@
namespace Code\Widget; namespace Code\Widget;
use App;
use Code\Render\Theme; use Code\Render\Theme;
@ -11,7 +10,6 @@ class Sblock implements WidgetInterface
public function widget(array $arguments): string public function widget(array $arguments): string
{ {
if (!local_channel()) { if (!local_channel()) {
return EMPTY_STR; return EMPTY_STR;
} }

View file

@ -20,26 +20,12 @@ class Settings_menu implements WidgetInterface
$channel = App::get_channel(); $channel = App::get_channel();
$abook_self_id = 0;
// Retrieve the 'self' address book entry for use in the auto-permissions link
$role = get_pconfig(local_channel(), 'system', 'permissions_role');
$abk = q(
"select abook_id from abook where abook_channel = %d and abook_self = 1 limit 1",
intval(local_channel())
);
if ($abk) {
$abook_self_id = $abk[0]['abook_id'];
}
$x = q( $x = q(
"select count(*) as total from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0 ", "select count(*) as total from hubloc where hubloc_hash = '%s' and hubloc_deleted = 0 ",
dbesc($channel['channel_hash']) dbesc($channel['channel_hash'])
); );
$hublocs = (($x && $x[0]['total'] > 1) ? true : false); $hublocs = $x && $x[0]['total'] > 1;
$tabs = [ $tabs = [
[ [
@ -89,14 +75,6 @@ class Settings_menu implements WidgetInterface
'selected' => '' 'selected' => ''
]; ];
// if(Features::enabled(local_channel(),'oauth_clients')) {
// $tabs[] = array(
// 'label' => t('OAuth1 apps'),
// 'url' => z_root() . '/settings/oauth',
// 'selected' => ((argv(1) === 'oauth') ? 'active' : ''),
// );
// }
if (Apps::system_app_installed(local_channel(), 'Clients')) { if (Apps::system_app_installed(local_channel(), 'Clients')) {
$tabs[] = [ $tabs[] = [
'label' => t('Client apps'), 'label' => t('Client apps'),
@ -105,41 +83,15 @@ class Settings_menu implements WidgetInterface
]; ];
} }
// if(Features::enabled(local_channel(),'access_tokens')) { if(Apps::system_app_installed(local_channel(),'Roles')) {
// $tabs[] = array(
// 'label' => t('Guest Access Tokens'),
// 'url' => z_root() . '/settings/tokens',
// 'selected' => ((argv(1) === 'tokens') ? 'active' : ''),
// );
// }
if(Apps::system_app_installed(local_channel(),'Roles')) {
$tabs[] = [ $tabs[] = [
'label' => t('Permission Roles'), 'label' => t('Permission Roles'),
'url' => z_root() . '/settings/permcats', 'url' => z_root() . '/settings/permcats',
'selected' => ((argv(1) === 'permcats') ? 'active' : ''), 'selected' => ((argv(1) === 'permcats') ? 'active' : ''),
]; ];
} }
return replace_macros(Theme::get_template('generic_links_widget.tpl'), [
// if($role === false || $role === 'custom') {
// $tabs[] = array(
// 'label' => t('Connection Default Permissions'),
// 'url' => z_root() . '/defperms',
// 'selected' => ''
// );
// }
// if(Features::enabled(local_channel(),'channel_sources')) {
// $tabs[] = array(
// 'label' => t('Channel Sources'),
// 'url' => z_root() . '/sources',
// 'selected' => ''
// );
// }
$tabtpl = Theme::get_template("generic_links_widget.tpl");
return replace_macros($tabtpl, [
'$title' => t('Settings'), '$title' => t('Settings'),
'$class' => 'settings-widget', '$class' => 'settings-widget',
'$items' => $tabs, '$items' => $tabs,

View file

@ -10,14 +10,13 @@ class Site_projects implements WidgetInterface
public function widget(array $arguments): string public function widget(array $arguments): string
{ {
$results = []; $results = [];
$query = q("select site_project, site_type, count(site_project) as total from site $query = q("select site_project, count(site_project) as total from site
where site_project != '' and site_flags != 256 and site_dead = 0 group by site_project, site_type order by site_project desc"); where site_project != '' and site_flags != 256 and site_dead = 0 group by site_project order by site_project desc");
if ($query) { if ($query) {
usort($query, ['self', 'site_sort']); usort($query, ['self', 'site_sort']);
foreach ($query as $rv) { foreach ($query as $rv) {
$result = []; $result = [];
$result['name'] = $rv['site_project']; $result['name'] = $rv['site_project'];
$result['type'] = $rv['site_type'];
$result['cname'] = ucfirst($result['name']); $result['cname'] = ucfirst($result['name']);
if ($rv['site_project'] === $_REQUEST['project']) { if ($rv['site_project'] === $_REQUEST['project']) {
$result['selected'] = true; $result['selected'] = true;
@ -26,17 +25,16 @@ class Site_projects implements WidgetInterface
$results[] = $result; $results[] = $result;
} }
$output = replace_macros(Theme::get_template('site_projects.tpl'), [ return replace_macros(Theme::get_template('site_projects.tpl'), [
'$title' => t('Community Types'), '$title' => t('Community Types'),
'$desc' => '', '$desc' => '',
'$all' => t('All community types'), '$all' => t('All community types'),
'base' => z_root() . '/communities', 'base' => z_root() . '/communities',
'$sel_all' => (($_REQUEST['project']) ? false : true), '$sel_all' => !$_REQUEST['project'],
'$terms' => $results '$terms' => $results
]); ]);
return $output;
} }
return '';
} }
public static function site_sort($a, $b) public static function site_sort($a, $b)

View file

@ -21,24 +21,21 @@ class Sitesearch implements WidgetInterface
$srchurl = str_replace(['?f=', '&f='], ['', ''], $srchurl); $srchurl = str_replace(['?f=', '&f='], ['', ''], $srchurl);
$hasq = ((str_contains($srchurl, '?')) ? true : false); $hasq = str_contains($srchurl, '?');
$hasamp = ((str_contains($srchurl, '&')) ? true : false); $hasamp = str_contains($srchurl, '&');
if (($hasamp) && (!$hasq)) { if (($hasamp) && (!$hasq)) {
$srchurl = substr($srchurl, 0, strpos($srchurl, '&')) . '?f=&' . substr($srchurl, strpos($srchurl, '&') + 1); $srchurl = substr($srchurl, 0, strpos($srchurl, '&')) . '?f=&' . substr($srchurl, strpos($srchurl, '&') + 1);
} }
$o = '';
$saved = []; $saved = [];
$tpl = Theme::get_template("sitesearch.tpl"); $tpl = Theme::get_template("sitesearch.tpl");
$o = replace_macros($tpl, [ return replace_macros($tpl, [
'$title' => t('Search'), '$title' => t('Search'),
'$searchbox' => searchbox($search, 'netsearch-box', $srchurl . (($hasq) ? '' : '?f='), false), '$searchbox' => searchbox($search, 'netsearch-box', $srchurl . (($hasq) ? '' : '?f=')),
'$saved' => $saved, '$saved' => $saved,
]); ]);
return $o;
} }
} }

View file

@ -37,9 +37,9 @@ class Suggestedchats implements WidgetInterface
$r[$x]['xchat_url'] = zid($r[$x]['xchat_url']); $r[$x]['xchat_url'] = zid($r[$x]['xchat_url']);
} }
} }
return replace_macros(Theme::get_template('bookmarkedchats.tpl'), array( return replace_macros(Theme::get_template('bookmarkedchats.tpl'), [
'$header' => t('Suggested Chatrooms'), '$header' => t('Suggested Chatrooms'),
'$rooms' => $r '$rooms' => $r
)); ]);
} }
} }

View file

@ -27,7 +27,7 @@ class Suggestions implements WidgetInterface
// Get two random entries from the top 20 returned. // Get two random entries from the top 20 returned.
// We'll grab the first one and the one immediately following. // We'll grab the first one and the one immediately following.
// This will throw some entropy into the situation so you won't // This will throw some entropy into the situation, so you won't
// be looking at the same two mug shots every time the widget runs // be looking at the same two mug shots every time the widget runs
$index = ((count($r) > 2) ? mt_rand(0, count($r) - 2) : 0); $index = ((count($r) > 2) ? mt_rand(0, count($r) - 2) : 0);
@ -52,12 +52,10 @@ class Suggestions implements WidgetInterface
]; ];
} }
$o = replace_macros(Theme::get_template('suggest_widget.tpl'), [ return replace_macros(Theme::get_template('suggest_widget.tpl'), [
'$title' => t('Suggestions'), '$title' => t('Suggestions'),
'$more' => t('See more...'), '$more' => t('See more...'),
'$entries' => $arguments '$entries' => $arguments
]); ]);
return $o;
} }
} }

View file

@ -18,6 +18,8 @@ Guest Pass: Provide special guest access to private resources and media - on you
Friend Zoom: Set your degree of closeness to any connection and then interactively zoom in to filter your stream to close friends; or zoom out to see posts by casual acquaintances. Friend Zoom: Set your degree of closeness to any connection and then interactively zoom in to filter your stream to close friends; or zoom out to see posts by casual acquaintances.
Location Services: Check-in, check-out, and search by distance
Delivery Reports: In a decentralised multi-platform world, stuff happens. Sites and networks sometimes go down. Project developers sometimes introduce bugs and incompatibilities. This allows you to determine what happened to your post or comment and where it actually went once you published it. Delivery Reports: In a decentralised multi-platform world, stuff happens. Sites and networks sometimes go down. Project developers sometimes introduce bugs and incompatibilities. This allows you to determine what happened to your post or comment and where it actually went once you published it.
Failsafe: Because the best time to have a current backup of your data is 10 seconds ago. Clone your online identity and content to multiple sites using the Nomad protocol and mirror any changes in near realtime. Then if your chosen site goes down (either temporarily or permanently) or you get booted off of it for some reason, your online life doesn't have to come to an end or force you to start over. All your friends and all your content are available on any of your cloned instances - at any time. Failsafe: Because the best time to have a current backup of your data is 10 seconds ago. Clone your online identity and content to multiple sites using the Nomad protocol and mirror any changes in near realtime. Then if your chosen site goes down (either temporarily or permanently) or you get booted off of it for some reason, your online life doesn't have to come to an end or force you to start over. All your friends and all your content are available on any of your cloned instances - at any time.

View file

@ -4,7 +4,7 @@ This repository first went public in 2010 and spawned a number of fediverse-rela
My name is Mike. I'm retired from open source now, but building decentralised communications software is what I do; and I've been doing it since before the web existed. So this isn't a hobby or get rich scheme - it's my life's mission and this repository is where I build and test new concepts and ideas. My name is Mike. I'm retired from open source now, but building decentralised communications software is what I do; and I've been doing it since before the web existed. So this isn't a hobby or get rich scheme - it's my life's mission and this repository is where I build and test new concepts and ideas.
From day one the question was how to build a federated/decentralised communication stack that provides more control over your privacy, and respects all people and cultures - including those which have a different political bias; while allowing them to all co-exist in the same space (and without killing each other). We've come up with lots of creative soutions to the thorniest of decentralisation problems over the intervening years. From day one the question was how to build a federated/decentralised communication stack that provides more control over your privacy, and respects all people and cultures - including those which have a different political bias; while allowing them to all co-exist in the same space (and without killing each other). We've come up with lots of creative solutions to the thorniest of decentralisation problems over the intervening years.
I'll highlight the most important ones: we implement cross-domain granular permissions and cross-domain (nomadic) identity and cross-domain single sign-on. All of these work together to provide a communications platform which is probably unlike any you have used before. It is fully decentralised, but provides many features that were previously only available from monolithic centralised systems. This is a huge distinction from many/most other fediverse projects and could represent a killer app for both the fediverse and the internet at large once adopted at scale. This is all coming to the internet anyway as it is a natural progression, except in our vision, your online existence belongs to you and not to Facebook, Twitter, Microsoft, and Google. I'll highlight the most important ones: we implement cross-domain granular permissions and cross-domain (nomadic) identity and cross-domain single sign-on. All of these work together to provide a communications platform which is probably unlike any you have used before. It is fully decentralised, but provides many features that were previously only available from monolithic centralised systems. This is a huge distinction from many/most other fediverse projects and could represent a killer app for both the fediverse and the internet at large once adopted at scale. This is all coming to the internet anyway as it is a natural progression, except in our vision, your online existence belongs to you and not to Facebook, Twitter, Microsoft, and Google.
@ -17,11 +17,11 @@ Single sign-on works with permissions to provide access to private media content
There are hundreds of other features available; but these are the defining features which have been constant for about the last decade. At one point there were so many features that we couldn't manage them all, so we simplified. Now the interface is much more sleek and basic; and you can add apps from our free app store to provide any advanced features you desire or require. There are hundreds of other features available; but these are the defining features which have been constant for about the last decade. At one point there were so many features that we couldn't manage them all, so we simplified. Now the interface is much more sleek and basic; and you can add apps from our free app store to provide any advanced features you desire or require.
Since 2017, every branch of this repository evolved to support communications over ActivityPub, the current web standard for social communications. This provides immediate access to (currently) around 5 million people across (currently) around a hundred different software applications. There are Twitter clones and Facebook clones and Instagram clones and YouTube clones - and we interact with all of them. In the interests of full disclosure, this repository first went public in 2010 as a decentralised Facebook alternative, but we've since turned it into something completely different and no longer care about emulating anybody or anything. We provide a communications experience with privacy mechanisms and features you simply won't find elsewhere. Since 2017, every branch of this repository evolved to support communications over ActivityPub, the current web standard for social communications. This provides immediate access to (currently) around 6 million people across (currently) around a hundred different software applications. There are Twitter clones and Facebook clones and Instagram clones and YouTube clones - and we interact with all of them. In the interests of full disclosure, this repository first went public in 2010 as a decentralised Facebook alternative, but we've since turned it into something completely different and no longer care about emulating anybody or anything. We provide a communications experience with privacy mechanisms and features you simply won't find elsewhere.
This software will install as a fediverse server using the LAMP stack. There are also containerised installations available (i.e. https://codeberg.org/node9/streams.docker). It is regularly maintained and updated and you are welcome to help - if you want. There is no formal organisation here. Either help out or don't. Many/most of our sites are privately run on small devices for family and friends and we don't know and don't care how many exist or how many "users" are on our systems. The servers themselves require very little ongoing maintenance and we spend a lot of effort providing a level playing field for all. You have the same features and abilities no matter how big (or small) your server is. This software will install as a fediverse server using the LAMP stack. It is regularly maintained and updated, and you are welcome to help - if you want. There are also containerised installations available (i.e. https://codeberg.org/node9/streams.docker). There is no formal organisation here. Either help out or don't. Many/most of our sites are privately run on small devices for family and friends, and we don't know and don't care how many exist or how many "users" are on our systems. The servers themselves require very little ongoing maintenance, and we spend a lot of effort providing a level playing field for all. You have the same features and abilities no matter how large (or small) your server is.
This work is dedicated and released to the public domain with no strings attached. Be advised that many others have contributed code to this repository under a number of different OSI-approved software licenses during its existence. This has no effect on any of your fundamental software freedoms; although corporate legal consultants who wish to re-appropriate our work for their employer's profit will likely find this lack of license clarity "troublesome". This is intentional. This work is dedicated and released to the public domain with no strings attached. Be advised that many others have contributed code to this repository under a number of different OSI-approved software licenses during its existence. This has no effect on any of your fundamental software freedoms; although corporate legal consultants who wish to re-appropriate our work for their employer's profit will likely find this lack of license clarity "troublesome". This is intentional.
The current name of this repository implies fluidity. As a brand or product it technically does not exist. This is also intentional. The software provides general web communications infrastructure. It's your website. Your site is your brand. Not ours. The current name of this repository implies fluidity. As a brand or product it technically does not exist. This is also intentional.

View file

@ -26,7 +26,7 @@ use Code\Lib\Url;
const REPOSITORY_ID = 'streams'; const REPOSITORY_ID = 'streams';
const DB_UPDATE_VERSION = 1263; const DB_UPDATE_VERSION = 1264;
const PROJECT_BASE = __DIR__; const PROJECT_BASE = __DIR__;
const ACTIVITYPUB_ENABLED = true; const ACTIVITYPUB_ENABLED = true;
const NOMAD_PROTOCOL_VERSION = '11.0'; const NOMAD_PROTOCOL_VERSION = '11.0';

View file

@ -2,7 +2,7 @@
## Disclaimer ## Disclaimer
- This script does work with Debian 10 or 11 only. - This script does work with Debian 11 only.
- This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation). You may use it to install more than one website on the same computer as long as you use a single webserver. - This script has to be used on a fresh debian install only (it does not take account for a possibly already installed and configured webserver or sql implementation). You may use it to install more than one website on the same computer as long as you use a single webserver.
## First step: setting up your system ## First step: setting up your system

View file

@ -1,4 +1,6 @@
# Easy install setup script # Easy install setup script
## This installation script was provided by the community and is untested and officially unsupported. Use at your own risk. Complaints have been made that it provides the wrong PHP version for the Streams repository, which requires PHP 8.0 or above. In case of difficulty, this would be the first thing to check. If you manage to fix the issue, please submit back to the repository so we can remove this warning.
Here you will find a quick and easy way to set up a website capable of joining the fediverse, using software from the Streams repository. All you have to do is run the setup script, enter some information and the magic will happen. Check the [INSTALL.md](INSTALL.md) file for step-by-step instructions. Here you will find a quick and easy way to set up a website capable of joining the fediverse, using software from the Streams repository. All you have to do is run the setup script, enter some information and the magic will happen. Check the [INSTALL.md](INSTALL.md) file for step-by-step instructions.

View file

@ -25,7 +25,7 @@
# under Debian Linux. It will: # under Debian Linux. It will:
# - install # - install
# * apache or nginx webserver, # * apache or nginx webserver,
# * php (adding sury repository to get php 8.* on Debian 11 or 10), # * php (adding sury repository to get php 8.* on Debian 11),
# * composer # * composer
# * mariadb - the database your website, # * mariadb - the database your website,
# * adminer, # * adminer,
@ -91,9 +91,9 @@ function check_sanity {
then then
die "Debian is supported only" die "Debian is supported only"
fi fi
if [ -z "$(grep 'Linux 10\|Linux 11' /etc/issue)" ] if [ -z "$(grep 'Linux 11' /etc/issue)" ]
then then
die "Debian 11 (bullseye) or Debian 10 (buster) are supported only" die "Debian 11 (bullseye) is supported only"
fi fi
} }

Some files were not shown because too many files have changed in this diff Show more