federator/php/federator/api/fedusers.php
Yannis Vogel 305ded4986
WIP inbox-support
- includes hacky following-mechanic in order to simulate a follow on mastodon (not properly working, need to also inject the user this creates into the followers db for the target mastodon-user)
- created endpoint for inbox. SharedInbox is used when no user is provided (/api/federator/fedusers/inbox'), the regular inbox link now works (/users/username/inbox).
- Retrieve all followers of sender and, if they're part of our system, send the activity into their personal inbox
- Support Announce and Undo Activity-Types
- Inbox currently converts to proper ActPub-objects and saves data to log-files
2025-04-15 16:42:46 +02:00

185 lines
5.7 KiB
PHP

<?php
/**
* SPDX-FileCopyrightText: 2024 Sascha Nitsch (grumpydeveloper) https://contentnation.net/@grumpydevelop
* SPDX-License-Identifier: GPL-3.0-or-later
*
* @author Sascha Nitsch (grumpydeveloper)
**/
namespace Federator\Api;
/**
* /@username or /users/ handlers
*/
class FedUsers implements APIInterface
{
/**
* main instance
*
* @var \Federator\Main $main
*/
private $main;
/**
* response from sub-calls
*
* @var string $response
*/
private $response;
/**
* constructor
*
* @param \Federator\Main $main main instance
* @return void
*/
public function __construct($main)
{
$this->main = $main;
}
/**
* run given url path
*
* @param array<string> $paths path array split by /
* @param \Federator\Data\User|false $user user who is calling us @unused-param
* @return bool true on success
*/
public function exec($paths, $user)
{
$method = $_SERVER["REQUEST_METHOD"];
$handler = null;
switch (sizeof($paths)) {
case 2:
if ($method === 'GET') {
// /fedusers/username or /@username
return $this->returnUserProfile($paths[1]);
} else {
switch ($paths[1]) {
case 'inbox':
$handler = new FedUsers\Inbox($this->main);
break;
default:
break;
}
}
break;
case 3:
// /fedusers/username/(inbox|outbox|following|followers)
switch ($paths[2]) {
case 'following':
// $handler = new FedUsers\Following();
break;
case 'followers':
// $handler = new FedUsers\Followers();
break;
case 'inbox':
$handler = new FedUsers\Inbox($this->main);
$user = $paths[1];
if (!preg_match("#^([^@]+)@([^/]+)#", $user, $matches) === 1) {
$hostUrl = $this->main->getHost();
if ($hostUrl !== false) {
$host = parse_url($hostUrl, PHP_URL_HOST);
$port = parse_url($hostUrl, PHP_URL_PORT);
if ($port !== null) {
$host .= `:$port`;
}
$user = `$user@$host`;
}
}
break;
case 'outbox':
$handler = new FedUsers\Outbox($this->main);
$user = $paths[1];
if (!preg_match("#^([^@]+)@([^/]+)#", $user, $matches) === 1) {
$hostUrl = $this->main->getHost();
if ($hostUrl !== false) {
$host = parse_url($hostUrl, PHP_URL_HOST);
$port = parse_url($hostUrl, PHP_URL_PORT);
if ($port !== null) {
$host .= `:$port`;
}
$user = `$user@$host`;
}
}
break;
}
break;
case 4:
// /fedusers/username/collections/(features|tags)
// not yet implemented
break;
}
if ($handler !== null) {
$ret = false;
switch ($method) {
case 'GET':
$ret = $handler->get($user);
break;
case 'POST':
$ret = $handler->post($user);
break;
}
if ($ret !== false) {
$this->response = $ret;
return true;
}
}
$this->main->setResponseCode(404);
return false;
}
/**
* return user profile
*
* @param string $_name
* @return boolean true on success
*/
private function returnUserProfile($_name)
{
$user = \Federator\DIO\User::getUserByName(
$this->main->getDatabase(),
$_name,
$this->main->getConnector(),
$this->main->getCache()
);
if ($user === false || $user->id === null) {
throw new \Federator\Exceptions\FileNotFound();
}
$data = [
'iconMediaType' => $user->iconMediaType,
'iconURL' => $user->iconURL,
'imageMediaType' => $user->imageMediaType,
'imageURL' => $user->imageURL,
'fqdn' => $_SERVER['SERVER_NAME'],
'name' => $user->name,
'username' => $user->id,
'publickey' => $user->publicKey,
'registered' => gmdate('Y-m-d\TH:i:s\Z', $user->registered), // 2021-03-25T00:00:00Z
'summary' => $user->summary,
'type' => $user->type
];
$this->response = $this->main->renderTemplate('user.json', $data);
return true;
}
/**
* set response
*
* @param string $response response to set
* @return void
*/
public function setResponse($response)
{
$this->response = $response;
}
/**
* get internal represenation as json string
* @return string json string or html
*/
public function toJson()
{
return $this->response;
}
}