use Friendica\Core\Logger;
use Friendica\Core\System;
use Friendica\DI;
+use Friendica\Model\Post;
use Friendica\Network\HTTPException;
use Friendica\Security\BasicAuth;
use Friendica\Security\OAuth;
+use Friendica\Util\Arrays;
+use Friendica\Util\DateTimeFormat;
use Friendica\Util\HTTPInputData;
+use Friendica\Util\XML;
require_once __DIR__ . '/../../include/api.php';
const SCOPE_FOLLOW = 'follow';
const SCOPE_PUSH = 'push';
- /**
- * @var string json|xml|rss|atom
- */
- protected static $format = 'json';
-
/**
* @var array
*/
*/
protected static $request = [];
- public static function init(array $parameters = [])
- {
- $arguments = DI::args();
-
- if (substr($arguments->getCommand(), -4) === '.xml') {
- self::$format = 'xml';
- }
- if (substr($arguments->getCommand(), -4) === '.rss') {
- self::$format = 'rss';
- }
- if (substr($arguments->getCommand(), -4) === '.atom') {
- self::$format = 'atom';
- }
- }
-
public static function delete(array $parameters = [])
{
self::checkAllowedScope(self::SCOPE_WRITE);
- $a = DI::app();
-
- if (!empty($a->user['uid']) && $a->user['uid'] != self::getCurrentUserID()) {
+ if (!DI::app()->isLoggedIn()) {
throw new HTTPException\ForbiddenException(DI::l10n()->t('Permission denied.'));
}
}
{
self::checkAllowedScope(self::SCOPE_WRITE);
- $a = DI::app();
-
- if (!empty($a->user['uid']) && $a->user['uid'] != self::getCurrentUserID()) {
+ if (!DI::app()->isLoggedIn()) {
throw new HTTPException\ForbiddenException(DI::l10n()->t('Permission denied.'));
}
}
{
self::checkAllowedScope(self::SCOPE_WRITE);
- $a = DI::app();
-
- if (!empty($a->user['uid']) && $a->user['uid'] != self::getCurrentUserID()) {
+ if (!DI::app()->isLoggedIn()) {
throw new HTTPException\ForbiddenException(DI::l10n()->t('Permission denied.'));
}
}
{
self::checkAllowedScope(self::SCOPE_WRITE);
- $a = DI::app();
-
- if (!empty($a->user['uid']) && $a->user['uid'] != self::getCurrentUserID()) {
+ if (!DI::app()->isLoggedIn()) {
throw new HTTPException\ForbiddenException(DI::l10n()->t('Permission denied.'));
}
}
- /**
- * Quit execution with the message that the endpoint isn't implemented
- *
- * @param string $method
- * @return void
- */
- public static function unsupported(string $method = 'all')
- {
- $path = DI::args()->getQueryString();
- Logger::info('Unimplemented API call', ['method' => $method, 'path' => $path, 'agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'request' => HTTPInputData::process()]);
- $error = DI::l10n()->t('API endpoint %s %s is not implemented', strtoupper($method), $path);
- $error_description = DI::l10n()->t('The API endpoint is currently not implemented but might be in the future.');
- $errorobj = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
- System::jsonError(501, $errorobj->toArray());
- }
-
/**
* Processes data from GET requests and sets defaults
*
*
* @return int User ID
*/
- protected static function getCurrentUserID()
+ public static function getCurrentUserID()
{
$uid = OAuth::getCurrentUserID();
}
}
+ public static function checkThrottleLimit()
+ {
+ $uid = self::getCurrentUserID();
+
+ // Check for throttling (maximum posts per day, week and month)
+ $throttle_day = DI::config()->get('system', 'throttle_limit_day');
+ if ($throttle_day > 0) {
+ $datefrom = date(DateTimeFormat::MYSQL, time() - 24*60*60);
+
+ $condition = ["`gravity` = ? AND `uid` = ? AND `wall` AND `received` > ?", GRAVITY_PARENT, $uid, $datefrom];
+ $posts_day = Post::countThread($condition);
+
+ if ($posts_day > $throttle_day) {
+ Logger::info('Daily posting limit reached', ['uid' => $uid, 'posts' => $posts_day, 'limit' => $throttle_day]);
+ $error = DI::l10n()->t('Too Many Requests');
+ $error_description = DI::l10n()->tt("Daily posting limit of %d post reached. The post was rejected.", "Daily posting limit of %d posts reached. The post was rejected.", $throttle_day);
+ $errorobj = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
+ System::jsonError(429, $errorobj->toArray());
+ }
+ }
+
+ $throttle_week = DI::config()->get('system', 'throttle_limit_week');
+ if ($throttle_week > 0) {
+ $datefrom = date(DateTimeFormat::MYSQL, time() - 24*60*60*7);
+
+ $condition = ["`gravity` = ? AND `uid` = ? AND `wall` AND `received` > ?", GRAVITY_PARENT, $uid, $datefrom];
+ $posts_week = Post::countThread($condition);
+
+ if ($posts_week > $throttle_week) {
+ Logger::info('Weekly posting limit reached', ['uid' => $uid, 'posts' => $posts_week, 'limit' => $throttle_week]);
+ $error = DI::l10n()->t('Too Many Requests');
+ $error_description = DI::l10n()->tt("Weekly posting limit of %d post reached. The post was rejected.", "Weekly posting limit of %d posts reached. The post was rejected.", $throttle_week);
+ $errorobj = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
+ System::jsonError(429, $errorobj->toArray());
+ }
+ }
+
+ $throttle_month = DI::config()->get('system', 'throttle_limit_month');
+ if ($throttle_month > 0) {
+ $datefrom = date(DateTimeFormat::MYSQL, time() - 24*60*60*30);
+
+ $condition = ["`gravity` = ? AND `uid` = ? AND `wall` AND `received` > ?", GRAVITY_PARENT, $uid, $datefrom];
+ $posts_month = Post::countThread($condition);
+
+ if ($posts_month > $throttle_month) {
+ Logger::info('Monthly posting limit reached', ['uid' => $uid, 'posts' => $posts_month, 'limit' => $throttle_month]);
+ $error = DI::l10n()->t('Too Many Requests');
+ $error_description = DI::l10n()->t("Monthly posting limit of %d post reached. The post was rejected.", "Monthly posting limit of %d posts reached. The post was rejected.", $throttle_month);
+ $errorobj = new \Friendica\Object\Api\Mastodon\Error($error, $error_description);
+ System::jsonError(429, $errorobj->toArray());
+ }
+ }
+ }
+
/**
* Get user info array.
*
*/
protected static function getUser($contact_id = null)
{
- return api_get_user(DI::app(), $contact_id);
- }
-
- /**
- * Formats the data according to the data type
- *
- * @param string $root_element
- * @param array $data An array with a single element containing the returned result
- * @return false|string
- */
- protected static function format(string $root_element, array $data)
- {
- $return = api_format_data($root_element, self::$format, $data);
-
- switch (self::$format) {
- case "xml":
- header("Content-Type: text/xml");
- break;
- case "json":
- header("Content-Type: application/json");
- if (!empty($return)) {
- $json = json_encode(end($return));
- if (!empty($_GET['callback'])) {
- $json = $_GET['callback'] . "(" . $json . ")";
- }
- $return = $json;
- }
- break;
- case "rss":
- header("Content-Type: application/rss+xml");
- $return = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $return;
- break;
- case "atom":
- header("Content-Type: application/atom+xml");
- $return = '<?xml version="1.0" encoding="UTF-8"?>' . "\n" . $return;
- break;
- }
-
- return $return;
- }
-
- /**
- * Creates the XML from a JSON style array
- *
- * @param $data
- * @param $root_element
- * @return string
- */
- protected static function createXml($data, $root_element)
- {
- return api_create_xml($data, $root_element);
+ return api_get_user($contact_id);
}
}