2017-07-17 05:28:28 +00:00
|
|
|
<?php
|
|
|
|
|
2022-02-16 04:08:28 +00:00
|
|
|
namespace Code\Lib;
|
2017-07-17 05:28:28 +00:00
|
|
|
|
2017-09-04 22:23:42 +00:00
|
|
|
/**
|
|
|
|
* @brief ActivityStreams class.
|
|
|
|
*
|
|
|
|
* Parses an ActivityStream JSON string.
|
|
|
|
*/
|
2021-12-02 23:02:31 +00:00
|
|
|
class ActivityStreams
|
|
|
|
{
|
|
|
|
|
|
|
|
public $raw = null;
|
|
|
|
public $data = null;
|
2022-02-05 22:07:10 +00:00
|
|
|
public $meta = null;
|
2021-12-02 23:02:31 +00:00
|
|
|
public $hub = null;
|
2022-03-14 10:09:03 +00:00
|
|
|
public $client = false;
|
2021-12-02 23:02:31 +00:00
|
|
|
public $valid = false;
|
|
|
|
public $deleted = false;
|
|
|
|
public $id = '';
|
|
|
|
public $parent_id = '';
|
|
|
|
public $type = '';
|
|
|
|
public $actor = null;
|
|
|
|
public $obj = null;
|
|
|
|
public $tgt = null;
|
|
|
|
public $replyto = null;
|
|
|
|
public $origin = null;
|
|
|
|
public $owner = null;
|
|
|
|
public $signer = null;
|
|
|
|
public $ldsig = null;
|
|
|
|
public $sigok = false;
|
|
|
|
public $recips = null;
|
|
|
|
public $raw_recips = null;
|
2022-08-13 10:57:14 +00:00
|
|
|
public $saved_recips = null;
|
|
|
|
public bool $implied_create = false;
|
2021-12-02 23:02:31 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Constructor for ActivityStreams.
|
|
|
|
*
|
|
|
|
* Takes a JSON string or previously decode activity array as parameter,
|
|
|
|
* decodes it and sets up this object/activity, fetching any required attributes
|
|
|
|
* which were only referenced by @id/URI.
|
|
|
|
*
|
2022-08-13 10:57:14 +00:00
|
|
|
* @param mixed $string
|
|
|
|
* @param null $hub
|
|
|
|
* @param null $client
|
2021-12-02 23:02:31 +00:00
|
|
|
*/
|
2023-05-04 11:37:49 +00:00
|
|
|
public function __construct(mixed $string, $hub = null, $client = null, $portable_id = null)
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
$this->raw = $string;
|
|
|
|
$this->hub = $hub;
|
2022-03-14 10:09:03 +00:00
|
|
|
$this->client = $client;
|
2023-05-04 11:37:49 +00:00
|
|
|
$this->portable_id = $portable_id;
|
2022-07-15 08:18:10 +00:00
|
|
|
|
2021-12-02 23:02:31 +00:00
|
|
|
if (is_array($string)) {
|
|
|
|
$this->data = $string;
|
|
|
|
$this->raw = json_encode($string, JSON_UNESCAPED_SLASHES);
|
|
|
|
} else {
|
|
|
|
$this->data = json_decode($string, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->data) {
|
2022-06-21 23:47:52 +00:00
|
|
|
// This indicates only that we have sucessfully decoded JSON.
|
|
|
|
$this->valid = true;
|
|
|
|
|
|
|
|
// Special handling for Mastodon "delete actor" activities which will often fail to verify
|
|
|
|
// because the key cannot be fetched. We will catch this condition elsewhere.
|
|
|
|
|
|
|
|
if (array_key_exists('type', $this->data) && array_key_exists('actor', $this->data) && array_key_exists('object', $this->data)) {
|
|
|
|
if ($this->data['type'] === 'Delete' && $this->data['actor'] === $this->data['object']) {
|
|
|
|
$this->deleted = $this->data['actor'];
|
|
|
|
$this->valid = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-02 23:02:31 +00:00
|
|
|
// verify and unpack JSalmon signature if present
|
|
|
|
// This will only be the case for Zot6 packets
|
|
|
|
|
2022-06-21 23:47:52 +00:00
|
|
|
if ($this->valid && is_array($this->data) && array_key_exists('signed', $this->data)) {
|
2021-12-02 23:02:31 +00:00
|
|
|
$ret = JSalmon::verify($this->data);
|
|
|
|
$tmp = JSalmon::unpack($this->data['data']);
|
2022-06-21 23:36:56 +00:00
|
|
|
if ($ret && $ret['success'] && $tmp) {
|
2021-12-02 23:02:31 +00:00
|
|
|
if ($ret['signer']) {
|
|
|
|
logger('Unpacked: ' . json_encode($tmp, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), LOGGER_DATA, LOG_DEBUG);
|
|
|
|
$saved = json_encode($this->data, JSON_UNESCAPED_SLASHES);
|
|
|
|
$this->data = $tmp;
|
2022-02-05 22:07:10 +00:00
|
|
|
$this->meta['signer'] = $ret['signer'];
|
|
|
|
$this->meta['signed_data'] = $saved;
|
2021-12-02 23:02:31 +00:00
|
|
|
if ($ret['hubloc']) {
|
2022-02-05 22:07:10 +00:00
|
|
|
$this->meta['hubloc'] = $ret['hubloc'];
|
2021-12-02 23:02:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-06-21 23:47:52 +00:00
|
|
|
else {
|
|
|
|
logger('JSalmon verification failure.');
|
2021-12-02 23:02:31 +00:00
|
|
|
$this->valid = false;
|
2022-07-15 08:18:10 +00:00
|
|
|
}
|
2021-12-02 23:02:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to assemble an Activity from what we were given.
|
|
|
|
|
|
|
|
if ($this->is_valid()) {
|
|
|
|
$this->id = $this->get_property_obj('id');
|
|
|
|
$this->type = $this->get_primary_type();
|
2022-08-13 10:57:14 +00:00
|
|
|
$this->actor = $this->get_actor('actor');
|
2021-12-02 23:02:31 +00:00
|
|
|
$this->obj = $this->get_compound_property('object');
|
|
|
|
$this->tgt = $this->get_compound_property('target');
|
|
|
|
$this->origin = $this->get_compound_property('origin');
|
|
|
|
$this->recips = $this->collect_recips();
|
|
|
|
$this->replyto = $this->get_property_obj('replyTo');
|
|
|
|
|
|
|
|
$this->ldsig = $this->get_compound_property('signature');
|
|
|
|
if ($this->ldsig) {
|
|
|
|
$this->signer = $this->get_compound_property('creator', $this->ldsig);
|
2021-12-03 03:01:39 +00:00
|
|
|
if (
|
|
|
|
$this->signer && is_array($this->signer) && array_key_exists('publicKey', $this->signer)
|
|
|
|
&& is_array($this->signer['publicKey']) && $this->signer['publicKey']['publicKeyPem']
|
|
|
|
) {
|
2021-12-02 23:02:31 +00:00
|
|
|
$this->sigok = LDSignatures::verify($this->data, $this->signer['publicKey']['publicKeyPem']);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Implied create activity required by C2S specification if no object is present
|
|
|
|
|
|
|
|
if (!$this->obj) {
|
|
|
|
if (!$client) {
|
|
|
|
$this->implied_create = true;
|
|
|
|
}
|
|
|
|
$this->obj = $this->data;
|
|
|
|
$this->type = 'Create';
|
|
|
|
if (!$this->actor) {
|
|
|
|
$this->actor = $this->get_actor('attributedTo', $this->obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// fetch recursive or embedded activities
|
|
|
|
|
|
|
|
if ($this->obj && is_array($this->obj) && array_key_exists('object', $this->obj)) {
|
2022-08-20 03:10:18 +00:00
|
|
|
$this->obj['object'] = $this->get_compound_property('object', $this->obj);
|
2021-12-02 23:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Enumerate and store actors in referenced objects
|
|
|
|
|
2022-01-09 22:01:18 +00:00
|
|
|
if ($this->obj && is_array($this->obj) && isset($this->obj['actor'])) {
|
2021-12-02 23:02:31 +00:00
|
|
|
$this->obj['actor'] = $this->get_actor('actor', $this->obj);
|
|
|
|
}
|
2022-01-09 22:01:18 +00:00
|
|
|
if ($this->tgt && is_array($this->tgt) && isset($this->tgt['actor'])) {
|
2021-12-02 23:02:31 +00:00
|
|
|
$this->tgt['actor'] = $this->get_actor('actor', $this->tgt);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Determine if this is a followup or response activity
|
|
|
|
|
|
|
|
$this->parent_id = $this->get_property_obj('inReplyTo');
|
|
|
|
|
|
|
|
if ((!$this->parent_id) && is_array($this->obj)) {
|
|
|
|
$this->parent_id = $this->obj['inReplyTo'];
|
|
|
|
}
|
|
|
|
if ((!$this->parent_id) && is_array($this->obj)) {
|
|
|
|
$this->parent_id = $this->obj['id'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Return if instantiated ActivityStream is valid.
|
|
|
|
*
|
|
|
|
* @return bool Return true if the JSON string could be decoded.
|
|
|
|
*/
|
|
|
|
|
2022-08-13 10:57:14 +00:00
|
|
|
public function is_valid(): bool
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
|
|
|
return $this->valid;
|
|
|
|
}
|
|
|
|
|
2022-08-13 10:57:14 +00:00
|
|
|
public function set_recips($arr): void
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
|
|
|
$this->saved_recips = $arr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Collects all recipients.
|
|
|
|
*
|
2022-08-14 09:32:01 +00:00
|
|
|
* @param mixed $base
|
2021-12-02 23:02:31 +00:00
|
|
|
* @param string $namespace (optional) default empty
|
|
|
|
* @return array
|
|
|
|
*/
|
2022-08-14 09:32:01 +00:00
|
|
|
public function collect_recips(mixed $base = '', string $namespace = ''): array
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
2022-07-18 11:51:54 +00:00
|
|
|
$result = [];
|
|
|
|
$tmp = [];
|
2022-07-20 05:27:23 +00:00
|
|
|
|
2021-12-02 23:02:31 +00:00
|
|
|
$fields = ['to', 'cc', 'bto', 'bcc', 'audience'];
|
2022-07-18 12:27:03 +00:00
|
|
|
foreach ($fields as $field) {
|
2021-12-02 23:02:31 +00:00
|
|
|
// don't expand these yet
|
2022-07-18 12:27:03 +00:00
|
|
|
$values = $this->get_property_obj($field, $base, $namespace);
|
|
|
|
if ($values) {
|
|
|
|
$values = Activity::force_array($values);
|
|
|
|
$tmp[$field] = $values;
|
|
|
|
$result = array_values(array_unique(array_merge($result, $values)));
|
2022-07-18 10:47:05 +00:00
|
|
|
}
|
|
|
|
// Merge the object recipients if they exist.
|
2022-07-18 12:27:03 +00:00
|
|
|
$values = $this->objprop($field);
|
|
|
|
if ($values) {
|
|
|
|
$values = Activity::force_array($values);
|
|
|
|
$tmp[$field] = (($tmp[$field]) ? array_merge($tmp[$field], $values) : $values);
|
|
|
|
$result = array_values(array_unique(array_merge($result, $values)));
|
2022-07-18 10:47:05 +00:00
|
|
|
}
|
2022-07-18 12:27:03 +00:00
|
|
|
// remove duplicates
|
|
|
|
if (is_array($tmp[$field])) {
|
|
|
|
$tmp[$field] = array_values(array_unique($tmp[$field]));
|
2021-12-02 23:02:31 +00:00
|
|
|
}
|
|
|
|
}
|
2022-07-18 12:27:03 +00:00
|
|
|
$this->raw_recips = $tmp;
|
2022-07-20 05:27:23 +00:00
|
|
|
|
2022-07-18 12:27:03 +00:00
|
|
|
// not yet ready for prime time
|
|
|
|
// $result = $this->expand($result,$base,$namespace);
|
2022-07-18 11:51:54 +00:00
|
|
|
return $result;
|
2021-12-02 23:02:31 +00:00
|
|
|
}
|
|
|
|
|
2022-08-13 10:57:14 +00:00
|
|
|
public function expand($arr, $base = '', $namespace = ''): array
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
|
|
|
$ret = [];
|
|
|
|
|
|
|
|
// right now use a hardwired recursion depth of 5
|
|
|
|
|
|
|
|
for ($z = 0; $z < 5; $z++) {
|
|
|
|
if (is_array($arr) && $arr) {
|
|
|
|
foreach ($arr as $a) {
|
|
|
|
if (is_array($a)) {
|
|
|
|
$ret[] = $a;
|
|
|
|
} else {
|
|
|
|
$x = $this->get_compound_property($a, $base, $namespace);
|
|
|
|
if ($x) {
|
2022-07-18 10:47:05 +00:00
|
|
|
$ret = array_values(array_unique(array_merge($ret, $x)));
|
2021-12-02 23:02:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief
|
|
|
|
*
|
2022-08-14 09:32:01 +00:00
|
|
|
* @param mixed $base
|
2021-12-02 23:02:31 +00:00
|
|
|
* @param string $namespace if not set return empty string
|
|
|
|
* @return string|NULL
|
|
|
|
*/
|
|
|
|
|
2022-08-14 09:32:01 +00:00
|
|
|
public function get_namespace(mixed $base, string $namespace): ?string
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
if (!$namespace) {
|
|
|
|
return EMPTY_STR;
|
|
|
|
}
|
|
|
|
|
|
|
|
$key = null;
|
|
|
|
|
|
|
|
foreach ([$this->data, $base] as $b) {
|
|
|
|
if (!$b) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (array_key_exists('@context', $b)) {
|
|
|
|
if (is_array($b['@context'])) {
|
|
|
|
foreach ($b['@context'] as $ns) {
|
|
|
|
if (is_array($ns)) {
|
|
|
|
foreach ($ns as $k => $v) {
|
|
|
|
if ($namespace === $v) {
|
|
|
|
$key = $k;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ($namespace === $ns) {
|
|
|
|
$key = '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ($namespace === $b['@context']) {
|
|
|
|
$key = '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $key;
|
|
|
|
}
|
|
|
|
|
2022-04-30 06:27:17 +00:00
|
|
|
/**
|
|
|
|
* @brief get single property from Activity object
|
|
|
|
*
|
|
|
|
* @param string $property
|
2022-07-15 08:18:10 +00:00
|
|
|
* @param mixed $default return value if property or object not set
|
2022-04-30 06:27:17 +00:00
|
|
|
* or object is a string id which could not be fetched.
|
|
|
|
* @return mixed
|
|
|
|
*/
|
2022-08-13 10:57:14 +00:00
|
|
|
public function objprop (string $property, mixed $default = false): mixed
|
|
|
|
{
|
2022-04-29 21:32:41 +00:00
|
|
|
$x = $this->get_property_obj($property,$this->obj);
|
|
|
|
return (isset($x)) ? $x : $default;
|
|
|
|
}
|
2022-07-15 08:18:10 +00:00
|
|
|
|
2021-12-02 23:02:31 +00:00
|
|
|
/**
|
|
|
|
* @brief
|
|
|
|
*
|
|
|
|
* @param string $property
|
2022-08-14 09:32:01 +00:00
|
|
|
* @param mixed $base (optional)
|
2021-12-02 23:02:31 +00:00
|
|
|
* @param string $namespace (optional) default empty
|
2022-08-13 10:57:14 +00:00
|
|
|
* @return mixed
|
2021-12-02 23:02:31 +00:00
|
|
|
*/
|
|
|
|
|
2022-08-14 09:32:01 +00:00
|
|
|
public function get_property_obj(string $property, mixed $base = '', string $namespace = ''): mixed
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
|
|
|
$prefix = $this->get_namespace($base, $namespace);
|
|
|
|
if ($prefix === null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2022-08-13 10:57:14 +00:00
|
|
|
$base = (($base) ?: $this->data);
|
2021-12-02 23:02:31 +00:00
|
|
|
$propname = (($prefix) ? $prefix . ':' : '') . $property;
|
|
|
|
|
2022-04-29 21:32:41 +00:00
|
|
|
return ((is_array($base) && array_key_exists($propname, $base)) ? $base[$propname] : null);
|
2021-12-02 23:02:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2022-08-13 10:57:14 +00:00
|
|
|
* @brief Fetches a property from a URL.
|
2021-12-02 23:02:31 +00:00
|
|
|
*
|
|
|
|
* @param string $url
|
2022-08-13 10:57:14 +00:00
|
|
|
* @param array|null $channel (signing channel, default system channel)
|
2021-12-02 23:02:31 +00:00
|
|
|
* @return NULL|mixed
|
|
|
|
*/
|
|
|
|
|
2022-10-09 05:10:31 +00:00
|
|
|
public function fetch_property(string $url, array $channel = null): mixed
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
2023-05-04 11:37:49 +00:00
|
|
|
if (str_starts_with($url, z_root() . '/item/')) {
|
|
|
|
$x = Activity::fetch_local($url, $this->portable_id ?? '');
|
2022-02-05 22:07:10 +00:00
|
|
|
}
|
2023-05-04 11:37:49 +00:00
|
|
|
if (!$x) {
|
|
|
|
$x = Activity::fetch($url, $channel);
|
|
|
|
if ($x === null && strpos($url, '/channel/')) {
|
|
|
|
// look for other nomadic channels which might be alive
|
|
|
|
$zf = Zotfinger::exec($url, $channel);
|
2022-02-05 22:07:10 +00:00
|
|
|
|
2023-05-04 11:37:49 +00:00
|
|
|
$url = $zf['signature']['signer'];
|
|
|
|
$x = Activity::fetch($url, $channel);
|
|
|
|
}
|
|
|
|
}
|
2022-02-05 22:07:10 +00:00
|
|
|
return $x;
|
2021-12-02 23:02:31 +00:00
|
|
|
}
|
|
|
|
|
2021-12-09 20:22:26 +00:00
|
|
|
/**
|
|
|
|
* @brief given a type, determine if this object represents an actor
|
2022-07-20 05:27:23 +00:00
|
|
|
*
|
|
|
|
* If $type is an array, recurse through each element and return true if any
|
|
|
|
* of the elements are a known actor type
|
|
|
|
*
|
2022-08-13 10:57:14 +00:00
|
|
|
* @param array|string $type
|
2022-07-20 05:27:23 +00:00
|
|
|
* @return boolean
|
|
|
|
*/
|
2021-12-09 20:22:26 +00:00
|
|
|
|
2022-09-16 20:04:38 +00:00
|
|
|
public static function is_an_actor(mixed $type): bool
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
2021-12-09 20:22:26 +00:00
|
|
|
if (!$type) {
|
2021-12-02 23:02:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
2022-07-20 05:27:23 +00:00
|
|
|
if (is_array($type)) {
|
|
|
|
foreach ($type as $x) {
|
|
|
|
if (self::is_an_actor($x)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2021-12-09 20:22:26 +00:00
|
|
|
return (in_array($type, ['Application', 'Group', 'Organization', 'Person', 'Service']));
|
2021-12-02 23:02:31 +00:00
|
|
|
}
|
|
|
|
|
2022-08-13 10:57:14 +00:00
|
|
|
public static function is_response_activity($s): bool
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
|
|
|
if (!$s) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return (in_array($s, ['Like', 'Dislike', 'Flag', 'Block', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'TentativeReject', 'emojiReaction', 'EmojiReaction', 'EmojiReact']));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief
|
|
|
|
*
|
|
|
|
* @param string $property
|
2022-08-14 09:32:01 +00:00
|
|
|
* @param mixed $base
|
2021-12-02 23:02:31 +00:00
|
|
|
* @param string $namespace (optional) default empty
|
|
|
|
* @return NULL|mixed
|
|
|
|
*/
|
|
|
|
|
2022-08-14 09:32:01 +00:00
|
|
|
public function get_actor(string $property, mixed $base = '', string $namespace = ''): mixed
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
|
|
|
$x = $this->get_property_obj($property, $base, $namespace);
|
|
|
|
if (self::is_url($x)) {
|
|
|
|
$y = Activity::get_cached_actor($x);
|
|
|
|
if ($y) {
|
|
|
|
return $y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$actor = $this->get_compound_property($property, $base, $namespace, true);
|
|
|
|
if (is_array($actor) && self::is_an_actor($actor['type'])) {
|
|
|
|
if (array_key_exists('id', $actor) && (!array_key_exists('inbox', $actor))) {
|
|
|
|
$actor = $this->fetch_property($actor['id']);
|
|
|
|
}
|
|
|
|
return $actor;
|
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief
|
|
|
|
*
|
|
|
|
* @param string $property
|
2022-08-14 09:32:01 +00:00
|
|
|
* @param mixed $base
|
2021-12-02 23:02:31 +00:00
|
|
|
* @param string $namespace (optional) default empty
|
|
|
|
* @param bool $first (optional) default false, if true and result is a sequential array return only the first element
|
|
|
|
* @return NULL|mixed
|
|
|
|
*/
|
|
|
|
|
2022-08-14 09:32:01 +00:00
|
|
|
public function get_compound_property(string $property, mixed $base = '', string $namespace = '', bool $first = false): mixed
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
|
|
|
$x = $this->get_property_obj($property, $base, $namespace);
|
|
|
|
if (self::is_url($x)) {
|
|
|
|
$y = $this->fetch_property($x);
|
|
|
|
if (is_array($y)) {
|
|
|
|
$x = $y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// verify and unpack JSalmon signature if present
|
|
|
|
// This may be present in Zot6 packets
|
|
|
|
|
|
|
|
if (is_array($x) && array_key_exists('signed', $x)) {
|
|
|
|
$ret = JSalmon::verify($x);
|
|
|
|
$tmp = JSalmon::unpack($x['data']);
|
|
|
|
if ($ret && $ret['success']) {
|
|
|
|
if ($ret['signer']) {
|
|
|
|
logger('Unpacked: ' . json_encode($tmp, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT), LOGGER_DATA, LOG_DEBUG);
|
|
|
|
$saved = json_encode($x, JSON_UNESCAPED_SLASHES);
|
|
|
|
$x = $tmp;
|
2022-02-05 22:07:10 +00:00
|
|
|
$x['meta']['signer'] = $ret['signer'];
|
|
|
|
$x['meta']['signed_data'] = $saved;
|
2021-12-02 23:02:31 +00:00
|
|
|
if ($ret['hubloc']) {
|
2022-02-05 22:07:10 +00:00
|
|
|
$x['meta']['hubloc'] = $ret['hubloc'];
|
2021-12-02 23:02:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ($first && is_array($x) && array_key_exists(0, $x)) {
|
|
|
|
return $x[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $x;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Check if string starts with http.
|
|
|
|
*
|
2022-08-13 10:57:14 +00:00
|
|
|
* @param mixed $url
|
2021-12-02 23:02:31 +00:00
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
|
2022-08-13 10:57:14 +00:00
|
|
|
public static function is_url(mixed $url): bool
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
2022-08-13 10:57:14 +00:00
|
|
|
if (($url) && (is_string($url)) && ((str_starts_with($url, 'http')) || (str_starts_with($url, 'x-zot')) || (str_starts_with($url, 'bear')))) {
|
2021-12-02 23:02:31 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Gets the type property.
|
|
|
|
*
|
2022-08-14 09:32:01 +00:00
|
|
|
* @param mixed $base
|
2021-12-02 23:02:31 +00:00
|
|
|
* @param string $namespace (optional) default empty
|
2022-08-13 10:57:14 +00:00
|
|
|
* @return mixed
|
2021-12-02 23:02:31 +00:00
|
|
|
*/
|
|
|
|
|
2022-08-14 09:32:01 +00:00
|
|
|
public function get_primary_type(mixed $base = '', string $namespace = ''): mixed
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
|
|
|
if (!$base) {
|
|
|
|
$base = $this->data;
|
|
|
|
}
|
|
|
|
$x = $this->get_property_obj('type', $base, $namespace);
|
|
|
|
if (is_array($x)) {
|
|
|
|
foreach ($x as $y) {
|
2022-08-13 10:57:14 +00:00
|
|
|
if (!str_contains($y, ':')) {
|
2021-12-02 23:02:31 +00:00
|
|
|
return $y;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $x;
|
|
|
|
}
|
|
|
|
|
2022-08-13 10:57:14 +00:00
|
|
|
public function debug() : null | string
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
2022-08-13 10:57:14 +00:00
|
|
|
return var_export($this, true);
|
2021-12-02 23:02:31 +00:00
|
|
|
}
|
|
|
|
|
2022-08-13 10:57:14 +00:00
|
|
|
public static function is_as_request() : bool
|
2021-12-02 23:02:31 +00:00
|
|
|
{
|
2023-03-19 10:40:56 +00:00
|
|
|
$default_accept_header = 'application/activity+json, application/x-zot-activity+json, application/ld+json; profile="https://www.w3.org/ns/activitystreams"';
|
2023-03-29 20:36:55 +00:00
|
|
|
$accept_header = Config::Get('system', 'accept_header', $default_accept_header);
|
2023-03-19 10:40:56 +00:00
|
|
|
|
|
|
|
$x = getBestSupportedMimeType(explode(',', $accept_header));
|
|
|
|
|
|
|
|
if (! $x) {
|
|
|
|
$x = getBestSupportedMimeType([
|
|
|
|
'application/ld+json;profile="https://www.w3.org/ns/activitystreams"',
|
|
|
|
'application/activity+json',
|
|
|
|
'application/ld+json;profile="http://www.w3.org/ns/activitystreams"',
|
|
|
|
'application/ld+json',
|
|
|
|
'application/x-zot-activity+json'
|
|
|
|
]);
|
|
|
|
}
|
2021-12-02 23:02:31 +00:00
|
|
|
|
2022-08-13 10:57:14 +00:00
|
|
|
return (bool)$x;
|
2021-12-02 23:02:31 +00:00
|
|
|
}
|
2021-12-03 03:01:39 +00:00
|
|
|
}
|