mirror of
https://codeberg.org/streams/streams.git
synced 2024-09-20 00:35:30 +00:00
Merge branch 'dev' of codeberg.org:streams/streams into dev
This commit is contained in:
commit
222b969c39
4 changed files with 388 additions and 13 deletions
|
@ -467,6 +467,11 @@ class Notifier implements DaemonInterface
|
|||
}
|
||||
$upstream = false;
|
||||
|
||||
if (Config::Get('system','2024')) {
|
||||
self::$encoded_item = array_merge(Activity::ap_context(), Activity::encode_add_activity($target_item, true));
|
||||
self::$encoded_item['signature'] = LDSignatures::sign(self::$encoded_item, self::$channel);
|
||||
}
|
||||
|
||||
if ($parent_item && $parent_item['item_private'] !== $target_item['item_private']) {
|
||||
logger('parent_item: ' . $parent_item['id'] . ' item_private: ' . $parent_item['item_private']);
|
||||
logger('target_item: ' . $target_item['id'] . ' item_private: ' . $target_item['item_private']);
|
||||
|
|
|
@ -353,7 +353,12 @@ class Activity
|
|||
if ($m) {
|
||||
$t = json_decode($m, true);
|
||||
} else {
|
||||
$t = self::encode_activity($i, $activitypub);
|
||||
if (Config::Get('system', '2024')) {
|
||||
$t = self::encode_add_activity($i, $activitypub);
|
||||
}
|
||||
else {
|
||||
$t = self::encode_activity($i, $activitypub);
|
||||
}
|
||||
}
|
||||
if ($t) {
|
||||
$x[] = $t;
|
||||
|
@ -1067,6 +1072,341 @@ class Activity
|
|||
}
|
||||
|
||||
|
||||
// the $recurse flag encodes the original non-deleted object of a deleted activity
|
||||
|
||||
public static function encode_add_activity($item, $activitypub = false, $recurse = false)
|
||||
{
|
||||
|
||||
$activity = [];
|
||||
|
||||
if (intval($item['item_deleted']) && (!$recurse)) {
|
||||
$is_response = ActivityStreams::is_response_activity($item['verb']);
|
||||
|
||||
if ($is_response) {
|
||||
$activity['type'] = 'Undo';
|
||||
$fragment = '#undo';
|
||||
} else {
|
||||
$activity['type'] = 'Delete';
|
||||
$fragment = '#delete';
|
||||
}
|
||||
|
||||
$activity['id'] = str_replace('/item/', '/activity/', $item['mid']) . $fragment;
|
||||
$actor = self::encode_person($item['author'], false);
|
||||
if ($actor) {
|
||||
$activity['actor'] = $actor;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
$obj = (($is_response) ? self::encode_add_activity($item, $activitypub, true) : self::encode_item($item, $activitypub));
|
||||
if ($obj) {
|
||||
if (array_path_exists('object/id', $obj)) {
|
||||
$obj['object'] = $obj['object']['id'];
|
||||
}
|
||||
if ($obj) {
|
||||
$activity['object'] = $obj;
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
$activity['to'] = [ACTIVITY_PUBLIC_INBOX];
|
||||
return $activity;
|
||||
}
|
||||
|
||||
$activity['type'] = 'Add';
|
||||
|
||||
if (str_contains($item['mid'], z_root() . '/item/')) {
|
||||
$activity['id'] = str_replace('/item/', '/activity/', $item['mid']);
|
||||
} elseif (str_contains($item['mid'], z_root() . '/event/')) {
|
||||
$activity['id'] = str_replace('/event/', '/activity/', $item['mid']);
|
||||
} else {
|
||||
$activity['id'] = $item['mid'];
|
||||
}
|
||||
|
||||
if ($item['title']) {
|
||||
$activity['name'] = $item['title'];
|
||||
}
|
||||
|
||||
if ($item['summary']) {
|
||||
$activity['summary'] = bbcode($item['summary'], ['export' => true]);
|
||||
}
|
||||
|
||||
if ($activity['type'] === 'Announce') {
|
||||
$tmp = $item['body'];
|
||||
$activity['content'] = bbcode($tmp, ['export' => true]);
|
||||
$activity['source'] = [
|
||||
'content' => $item['body'],
|
||||
'mediaType' => 'text/x-multicode'
|
||||
];
|
||||
if ($item['summary']) {
|
||||
$activity['source']['summary'] = $item['summary'];
|
||||
}
|
||||
}
|
||||
|
||||
$activity['published'] = datetime_convert('UTC', 'UTC', $item['created'], ATOM_TIME);
|
||||
if ($item['created'] !== $item['edited']) {
|
||||
$activity['updated'] = datetime_convert('UTC', 'UTC', $item['edited'], ATOM_TIME);
|
||||
if ($activity['type'] === 'Create') {
|
||||
$activity['type'] = 'Update';
|
||||
}
|
||||
}
|
||||
if ($item['app']) {
|
||||
$activity['generator'] = ['type' => 'Application', 'name' => $item['app']];
|
||||
}
|
||||
if ($item['location'] || $item['lat'] || $item['lon']) {
|
||||
$place = (new Place())->setType('Place')
|
||||
->setName(isset($item['location']) ? $item['location'] : null);
|
||||
if ($item['lat'] || $item['lon']) {
|
||||
$place->setLatitude(isset($item['lat']) ? $item['lat'] : 0)
|
||||
->setLongitude(isset($item['lon']) ? $item['lon'] : 0);
|
||||
}
|
||||
$activity['location'] = $place->toArray();
|
||||
}
|
||||
|
||||
if ($item['mid'] === $item['parent_mid']) {
|
||||
$activity['isContainedConversation'] = true;
|
||||
}
|
||||
else {
|
||||
// inReplyTo needs to be set in the activity for followup actions (Like, Dislike, Announce, etc.),
|
||||
// but *not* for comments and RSVPs, where it should only be present in the object
|
||||
|
||||
if (!in_array($activity['type'], ['Create', 'Update'])) {
|
||||
$activity['inReplyTo'] = $item['thr_parent'];
|
||||
}
|
||||
|
||||
if (in_array($activity['type'], ['Accept', 'Reject', 'TentativeAccept', 'TentativeReject'])) {
|
||||
$activity['inReplyTo'] = set_activity_mid($item['thr_parent']);
|
||||
}
|
||||
|
||||
// @FIXME FEP-5624 set for comment approvals but not event approvals
|
||||
// For comment approvals and rejections
|
||||
// if (in_array($activity['type'], ['Accept','Reject']) && is_string($item['obj']) && strlen($item['obj'])) {
|
||||
// $activity['inReplyTo'] = $item['thr_parent'];
|
||||
// }
|
||||
|
||||
$cnv = get_iconfig($item['parent'], 'activitypub', 'context');
|
||||
if (!$cnv) {
|
||||
$cnv = $item['parent_mid'];
|
||||
}
|
||||
}
|
||||
|
||||
if (!(isset($cnv) && $cnv)) {
|
||||
$cnv = get_iconfig($item, 'activitypub', 'context');
|
||||
if (!$cnv) {
|
||||
$cnv = $item['parent_mid'];
|
||||
}
|
||||
}
|
||||
if (!empty($cnv)) {
|
||||
if (is_string($cnv) && str_starts_with($cnv, z_root())) {
|
||||
$cnv = str_replace(['/item/', '/activity/'], ['/conversation/', '/conversation/'], $cnv);
|
||||
}
|
||||
$activity['context'] = $cnv;
|
||||
$activity['conversation'] = $cnv;
|
||||
}
|
||||
|
||||
if (intval($item['item_private']) === 2) {
|
||||
$activity['directMessage'] = true;
|
||||
}
|
||||
|
||||
$actor = self::encode_person($item['owner'], false);
|
||||
if ($actor) {
|
||||
$activity['actor'] = $actor;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
$replyTo = unserialise($item['replyto']);
|
||||
if ($replyTo) {
|
||||
$activity['replyTo'] = $replyTo;
|
||||
$activity['audience'] = $replyTo;
|
||||
}
|
||||
|
||||
if (!isset($activity['url'])) {
|
||||
$urls = [];
|
||||
if (intval($item['item_wall'])) {
|
||||
$locs = self::nomadic_locations($item);
|
||||
if ($locs) {
|
||||
foreach ($locs as $l) {
|
||||
if (str_contains($activity['id'], $l['hubloc_url'])) {
|
||||
continue;
|
||||
}
|
||||
$urls[] = [
|
||||
'type' => 'Link',
|
||||
'href' => str_replace(z_root(), $l['hubloc_url'], $activity['id']),
|
||||
'rel' => 'alternate',
|
||||
'mediaType' => 'text/html'
|
||||
];
|
||||
$urls[] = [
|
||||
'type' => 'Link',
|
||||
'href' => str_replace(z_root(), $l['hubloc_url'], $activity['id']),
|
||||
'rel' => 'alternate',
|
||||
'mediaType' => 'application/activity+json'
|
||||
];
|
||||
$urls[] = [
|
||||
'type' => 'Link',
|
||||
'href' => str_replace(z_root(), $l['hubloc_url'], $activity['id']),
|
||||
'rel' => 'alternate',
|
||||
'mediaType' => 'application/x-zot+json'
|
||||
];
|
||||
$urls[] = [
|
||||
'type' => 'Link',
|
||||
'href' => str_replace(z_root(), $l['hubloc_url'], $activity['id']),
|
||||
'rel' => 'alternate',
|
||||
'mediaType' => 'application/x-nomad+json'
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($urls) {
|
||||
$curr[] = [
|
||||
'type' => 'Link',
|
||||
'href' => $activity['id'],
|
||||
'rel' => 'alternate',
|
||||
'mediaType' => 'text/html'
|
||||
];
|
||||
$activity['url'] = array_merge($curr, $urls);
|
||||
} else {
|
||||
$activity['url'] = $activity['id'];
|
||||
}
|
||||
}
|
||||
|
||||
if ($item['obj']) {
|
||||
if (is_string($item['obj'])) {
|
||||
$tmp = json_decode($item['obj'], true);
|
||||
if ($tmp !== null) {
|
||||
$item['obj'] = $tmp;
|
||||
}
|
||||
}
|
||||
$obj = self::encode_object($item['obj']);
|
||||
}
|
||||
else {
|
||||
$obj = self::encode_item($item, $activitypub);
|
||||
}
|
||||
if ($obj) {
|
||||
$activity['object'] = $obj;
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
||||
if ($item['target']) {
|
||||
if (is_string($item['target'])) {
|
||||
$tmp = json_decode($item['target'], true);
|
||||
if ($tmp !== null) {
|
||||
$item['target'] = $tmp;
|
||||
}
|
||||
}
|
||||
$tgt = self::encode_object($item['target']);
|
||||
if ($tgt) {
|
||||
$activity['target'] = $tgt;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$activity['target'] = $activity['context'];
|
||||
}
|
||||
|
||||
$t = self::encode_taxonomy($item);
|
||||
if ($t) {
|
||||
foreach($t as $tag) {
|
||||
if (strcasecmp($tag['name'], '#nsfw') === 0
|
||||
|| strcasecmp($tag['name'], '#sensitive') === 0) {
|
||||
$activity['sensitive'] = true;
|
||||
}
|
||||
}
|
||||
$activity['tag'] = $t;
|
||||
}
|
||||
|
||||
if ($obj && $obj['attachment']) {
|
||||
$activity['attachment'] = $obj['attachment'];
|
||||
}
|
||||
else {
|
||||
$a = self::encode_attachment($item);
|
||||
if ($a) {
|
||||
$activity['attachment'] = $a;
|
||||
}
|
||||
}
|
||||
|
||||
// addressing madness
|
||||
|
||||
if ($activitypub) {
|
||||
$parent_i = [];
|
||||
$public = !$item['item_private'];
|
||||
$top_level = ($item['mid'] === $item['parent_mid']);
|
||||
$activity['to'] = [];
|
||||
$activity['cc'] = [];
|
||||
|
||||
$recips = get_iconfig($item['parent'], 'activitypub', 'recips');
|
||||
if ($recips) {
|
||||
$parent_i['to'] = $recips['to'];
|
||||
$parent_i['cc'] = $recips['cc'];
|
||||
}
|
||||
|
||||
if ($public) {
|
||||
$activity['to'] = [ACTIVITY_PUBLIC_INBOX];
|
||||
if (isset($parent_i['to']) && is_array($parent_i['to'])) {
|
||||
$activity['to'] = array_values(array_unique(array_merge($activity['to'], $parent_i['to'])));
|
||||
}
|
||||
if ($item['item_origin']) {
|
||||
$activity['cc'] = [z_root() . '/followers/' . substr($item['author']['xchan_addr'], 0, strpos($item['author']['xchan_addr'], '@'))];
|
||||
}
|
||||
if (isset($parent_i['cc']) && is_array($parent_i['cc'])) {
|
||||
$activity['cc'] = array_values(array_unique(array_merge($activity['cc'], $parent_i['cc'])));
|
||||
}
|
||||
} else {
|
||||
// private activity
|
||||
if ($top_level) {
|
||||
$activity['to'] = self::map_acl($item);
|
||||
if (isset($parent_i['to']) && is_array($parent_i['to'])) {
|
||||
$activity['to'] = array_values(array_unique(array_merge($activity['to'], $parent_i['to'])));
|
||||
}
|
||||
} elseif ((int)$item_private === 1) {
|
||||
$activity['cc'] = self::map_acl($item);
|
||||
if (isset($parent_i['cc']) && is_array($parent_i['cc'])) {
|
||||
$activity['cc'] = array_values(array_unique(array_merge($activity['cc'], $parent_i['cc'])));
|
||||
}
|
||||
|
||||
$d = q(
|
||||
"select hubloc.* from hubloc left join item on hubloc_hash = owner_xchan where item.parent_mid = '%s' and item.uid = %d and hubloc_deleted = 0 order by hubloc_id desc limit 1",
|
||||
dbesc($item['parent_mid']),
|
||||
intval($item['uid'])
|
||||
);
|
||||
if ($d) {
|
||||
if ($d[0]['hubloc_network'] === 'activitypub') {
|
||||
$addr = $d[0]['hubloc_hash'];
|
||||
} else {
|
||||
$addr = $d[0]['hubloc_id_url'];
|
||||
}
|
||||
$activity['cc'][] = $addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$mentions = self::map_mentions($item);
|
||||
if (count($mentions) > 0) {
|
||||
if (!$activity['to']) {
|
||||
$activity['to'] = $mentions;
|
||||
} else {
|
||||
$activity['to'] = array_values(array_unique(array_merge($activity['to'], $mentions)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$cc = [];
|
||||
if ($activity['cc'] && is_array($activity['cc'])) {
|
||||
foreach ($activity['cc'] as $e) {
|
||||
if (!is_array($activity['to'])) {
|
||||
$cc[] = $e;
|
||||
} elseif (!in_array($e, $activity['to'])) {
|
||||
$cc[] = $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
$activity['cc'] = $cc;
|
||||
|
||||
return $activity;
|
||||
}
|
||||
|
||||
|
||||
public static function nomadic_locations($item)
|
||||
{
|
||||
$synchubs = [];
|
||||
|
@ -1710,10 +2050,12 @@ class Activity
|
|||
];
|
||||
|
||||
$ret['assertionMethod'] = [
|
||||
'id' => $current_url . '?operation=ed25519key',
|
||||
'type' => 'Multikey',
|
||||
'controller' => $current_url,
|
||||
'publicKeyMultibase' => (new Multibase())->publicKey($c['channel_epubkey'])
|
||||
[
|
||||
'id' => $current_url . '?operation=ed25519key',
|
||||
'type' => 'Multikey',
|
||||
'controller' => $current_url,
|
||||
'publicKeyMultibase' => (new Multibase())->publicKey($c['channel_epubkey'])
|
||||
]
|
||||
];
|
||||
|
||||
$ret['manuallyApprovesFollowers'] = !$auto_follow;
|
||||
|
|
|
@ -16,23 +16,45 @@ class Config
|
|||
* @param string $family
|
||||
* The category of the configuration value
|
||||
*/
|
||||
public static function Load($family)
|
||||
public static function Load($family, $recursionCounter = 0)
|
||||
{
|
||||
if (! array_key_exists($family, App::$config)) {
|
||||
App::$config[$family] = [];
|
||||
}
|
||||
|
||||
// We typically continue when presented with minor DB issues,
|
||||
// but loading the site configuration is more important.
|
||||
|
||||
// Check for query returning false and give it approx 30 seconds
|
||||
// to recover if there's a problem. This is intended to fix a
|
||||
// rare issue on Galera where temporary sync issues were causing
|
||||
// the site encryption keys to be regenerated, which was causing
|
||||
// communication issues for members.
|
||||
|
||||
// This code probably belongs at the database layer, but we don't
|
||||
// necessarily want to shut the site down for problematic queries
|
||||
// caused by bad data. That could be used in a denial of service
|
||||
// attack. Those do need to be (and they are) logged.
|
||||
|
||||
if (! array_key_exists('config_loaded', App::$config[$family])) {
|
||||
$r = q("SELECT * FROM config WHERE cat = '%s'", dbesc($family));
|
||||
if ($r !== false) {
|
||||
if ($r) {
|
||||
foreach ($r as $rr) {
|
||||
$k = $rr['k'];
|
||||
App::$config[$family][$k] = $rr['v'];
|
||||
}
|
||||
if ($r === false) {
|
||||
sleep(3);
|
||||
$recursionCounter ++;
|
||||
if ($recursionCounter > 10) {
|
||||
system_unavailable();
|
||||
}
|
||||
self::Load($family, $recursionCounter);
|
||||
}
|
||||
else {
|
||||
foreach ($r as $rr) {
|
||||
$k = $rr['k'];
|
||||
App::$config[$family][$k] = $rr['v'];
|
||||
}
|
||||
App::$config[$family]['config_loaded'] = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
namespace Code\Module;
|
||||
|
||||
use Code\Lib\Config;
|
||||
use Code\Lib\IConfig;
|
||||
use Code\Web\Controller;
|
||||
use Code\Lib\ActivityStreams;
|
||||
|
@ -120,7 +121,12 @@ class Activity extends Controller
|
|||
|
||||
$channel = Channel::from_id($items[0]['uid']);
|
||||
|
||||
as_return_and_die(ZlibActivity::encode_activity($items[0], true), $channel);
|
||||
if (Config::Get('system','2024')) {
|
||||
as_return_and_die(ZlibActivity::encode_add_activity($items[0], true), $channel);
|
||||
}
|
||||
else {
|
||||
as_return_and_die(ZlibActivity::encode_activity($items[0], true), $channel);
|
||||
}
|
||||
}
|
||||
|
||||
if (Libzot::is_nomad_request()) {
|
||||
|
|
Loading…
Reference in a new issue