From e3d227f3c9b9bbb363d34033e4fd3f909697a967 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 19 May 2021 06:18:42 +0000 Subject: [PATCH 1/4] API: Parameter cleanup --- src/Module/Api/Friendica/Events/Index.php | 10 ++-- .../Api/Mastodon/Accounts/Followers.php | 2 + .../Api/Mastodon/Accounts/Following.php | 4 +- src/Module/Api/Mastodon/Accounts/Note.php | 6 ++- .../Api/Mastodon/Accounts/Relationships.php | 8 +++- src/Module/Api/Mastodon/Accounts/Statuses.php | 4 +- src/Module/Api/Mastodon/Blocks.php | 2 + src/Module/Api/Mastodon/Bookmarks.php | 10 ++-- src/Module/Api/Mastodon/Favourited.php | 4 +- src/Module/Api/Mastodon/Lists.php | 11 +++-- src/Module/Api/Mastodon/Lists/Accounts.php | 4 +- src/Module/Api/Mastodon/Mutes.php | 2 + src/Module/Api/Mastodon/Notifications.php | 2 +- src/Module/Api/Mastodon/Search.php | 4 +- src/Module/Api/Mastodon/Suggestions.php | 7 +-- src/Module/Api/Mastodon/Timelines/Home.php | 20 +++++++- .../Api/Mastodon/Timelines/ListTimeline.php | 20 +++++++- .../Api/Mastodon/Timelines/PublicTimeline.php | 2 +- src/Module/Api/Mastodon/Timelines/Tag.php | 46 ++++++++++--------- src/Module/Api/Mastodon/Trends.php | 7 +-- src/Module/OAuth/Authorize.php | 24 +++++----- src/Module/OAuth/Token.php | 28 +++++------ 22 files changed, 147 insertions(+), 80 deletions(-) diff --git a/src/Module/Api/Friendica/Events/Index.php b/src/Module/Api/Friendica/Events/Index.php index 3efa1a919e..53408541a2 100644 --- a/src/Module/Api/Friendica/Events/Index.php +++ b/src/Module/Api/Friendica/Events/Index.php @@ -39,11 +39,13 @@ class Index extends BaseApi throw new HTTPException\ForbiddenException(); } - $since_id = $_REQUEST['since_id'] ?? 0; - $count = $_REQUEST['count'] ?? 20; + $request = self::getRequest([ + 'since_id' => 0, + 'count' => 0, + ]); - $condition = ["`id` > ? AND `uid` = ?", $since_id, self::$current_user_id]; - $params = ['limit' => $count]; + $condition = ["`id` > ? AND `uid` = ?", $request['since_id'], self::$current_user_id]; + $params = ['limit' => $request['count']]; $events = DBA::selectToArray('event', [], $condition, $params); $items = []; diff --git a/src/Module/Api/Mastodon/Accounts/Followers.php b/src/Module/Api/Mastodon/Accounts/Followers.php index 67f57cb29e..65bb3d75f7 100644 --- a/src/Module/Api/Mastodon/Accounts/Followers.php +++ b/src/Module/Api/Mastodon/Accounts/Followers.php @@ -49,6 +49,8 @@ class Followers extends BaseApi DI::mstdnError()->RecordNotFound(); } + // @todo provide HTTP link header + $request = self::getRequest([ 'max_id' => 0, // Return results older than this id 'since_id' => 0, // Return results newer than this id diff --git a/src/Module/Api/Mastodon/Accounts/Following.php b/src/Module/Api/Mastodon/Accounts/Following.php index 582f84d7fe..42b9da4b44 100644 --- a/src/Module/Api/Mastodon/Accounts/Following.php +++ b/src/Module/Api/Mastodon/Accounts/Following.php @@ -49,10 +49,12 @@ class Following extends BaseApi DI::mstdnError()->RecordNotFound(); } + // @todo provide HTTP link header + $request = self::getRequest([ 'max_id' => 0, // Return results older than this id 'since_id' => 0, // Return results newer than this id - 'limit' => 20, // Maximum number of results to return. Defaults to 20. + 'limit' => 40, // Maximum number of results to return. Defaults to 40. ]); $params = ['order' => ['relation-cid' => true], 'limit' => $request['limit']]; diff --git a/src/Module/Api/Mastodon/Accounts/Note.php b/src/Module/Api/Mastodon/Accounts/Note.php index 1f3dd8d91c..477bcb8246 100644 --- a/src/Module/Api/Mastodon/Accounts/Note.php +++ b/src/Module/Api/Mastodon/Accounts/Note.php @@ -41,12 +41,16 @@ class Note extends BaseApi DI::mstdnError()->UnprocessableEntity(); } + $request = self::getRequest([ + 'comment' => '', + ]); + $cdata = Contact::getPublicAndUserContacID($parameters['id'], $uid); if (empty($cdata['user'])) { DI::mstdnError()->RecordNotFound(); } - DBA::update('contact', ['info' => $_REQUEST['comment'] ?? ''], ['id' => $cdata['user']]); + DBA::update('contact', ['info' => $request['comment']], ['id' => $cdata['user']]); System::jsonExit(DI::mstdnRelationship()->createFromContactId($parameters['id'], $uid)->toArray()); } diff --git a/src/Module/Api/Mastodon/Accounts/Relationships.php b/src/Module/Api/Mastodon/Accounts/Relationships.php index c134adf481..9e966d2152 100644 --- a/src/Module/Api/Mastodon/Accounts/Relationships.php +++ b/src/Module/Api/Mastodon/Accounts/Relationships.php @@ -40,13 +40,17 @@ class Relationships extends BaseApi self::login(self::SCOPE_READ); $uid = self::getCurrentUserID(); - if (empty($_REQUEST['id']) || !is_array($_REQUEST['id'])) { + $request = self::getRequest([ + 'id' => [], + ]); + + if (empty($request['id']) || !is_array($request['id'])) { DI::mstdnError()->UnprocessableEntity(); } $relationsships = []; - foreach ($_REQUEST['id'] as $id) { + foreach ($request['id'] as $id) { $relationsships[] = DI::mstdnRelationship()->createFromContactId($id, $uid); } diff --git a/src/Module/Api/Mastodon/Accounts/Statuses.php b/src/Module/Api/Mastodon/Accounts/Statuses.php index e2aeade550..07a1e5adc2 100644 --- a/src/Module/Api/Mastodon/Accounts/Statuses.php +++ b/src/Module/Api/Mastodon/Accounts/Statuses.php @@ -59,7 +59,9 @@ class Statuses extends BaseApi 'limit' => 20, // Maximum number of results to return. Defaults to 20. 'pinned' => false, // Only pinned posts 'exclude_replies' => false, // Don't show comments - 'with_muted' => false, // Unknown parameter + 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. + 'exclude_reblogs' => false, // Undocumented parameter + 'tagged' => false, // Undocumented parameter ]); $params = ['order' => ['uri-id' => true], 'limit' => $request['limit']]; diff --git a/src/Module/Api/Mastodon/Blocks.php b/src/Module/Api/Mastodon/Blocks.php index b1d802d053..651589f649 100644 --- a/src/Module/Api/Mastodon/Blocks.php +++ b/src/Module/Api/Mastodon/Blocks.php @@ -49,6 +49,8 @@ class Blocks extends BaseApi DI::mstdnError()->RecordNotFound(); } + // @todo provide HTTP link header + $request = self::getRequest([ 'max_id' => 0, // Return results older than this id 'since_id' => 0, // Return results newer than this id diff --git a/src/Module/Api/Mastodon/Bookmarks.php b/src/Module/Api/Mastodon/Bookmarks.php index 90afbc1d36..fa8f01f924 100644 --- a/src/Module/Api/Mastodon/Bookmarks.php +++ b/src/Module/Api/Mastodon/Bookmarks.php @@ -43,11 +43,11 @@ class Bookmarks extends BaseApi $uid = self::getCurrentUserID(); $request = self::getRequest([ - 'limit' => 20, // Maximum number of results to return. Defaults to 20. - 'max_id' => 0, // Return results older than id - 'since_id' => 0, // Return results newer than id - 'min_id' => 0, // Return results immediately newer than id - 'with_muted' => false, // Unknown parameter + 'limit' => 20, // Maximum number of results to return. Defaults to 20. + 'max_id' => 0, // Return results older than id + 'since_id' => 0, // Return results newer than id + 'min_id' => 0, // Return results immediately newer than id + 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. ]); $params = ['order' => ['uri-id' => true], 'limit' => $request['limit']]; diff --git a/src/Module/Api/Mastodon/Favourited.php b/src/Module/Api/Mastodon/Favourited.php index b5bd78690b..2b01c95fc9 100644 --- a/src/Module/Api/Mastodon/Favourited.php +++ b/src/Module/Api/Mastodon/Favourited.php @@ -43,11 +43,13 @@ class Favourited extends BaseApi self::login(self::SCOPE_READ); $uid = self::getCurrentUserID(); + // @todo provide HTTP link header + $request = self::getRequest([ 'limit' => 20, // Maximum number of results to return. Defaults to 20. 'min_id' => 0, // Return results immediately newer than id 'max_id' => 0, // Return results older than id - 'with_muted' => false, // Unknown parameter + 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. ]); $params = ['order' => ['thr-parent-id' => true], 'limit' => $request['limit']]; diff --git a/src/Module/Api/Mastodon/Lists.php b/src/Module/Api/Mastodon/Lists.php index 496550d4a7..5681ebf8a9 100644 --- a/src/Module/Api/Mastodon/Lists.php +++ b/src/Module/Api/Mastodon/Lists.php @@ -57,15 +57,18 @@ class Lists extends BaseApi self::login(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); - $title = $_REQUEST['title'] ?? ''; - if (empty($title)) { + $request = self::getRequest([ + 'title' => '', + ]); + + if (empty($request['title'])) { DI::mstdnError()->UnprocessableEntity(); } - Group::create($uid, $title); + Group::create($uid, $request['title']); - $id = Group::getIdByName($uid, $title); + $id = Group::getIdByName($uid, $request['title']); if (!$id) { DI::mstdnError()->InternalError(); } diff --git a/src/Module/Api/Mastodon/Lists/Accounts.php b/src/Module/Api/Mastodon/Lists/Accounts.php index 16b1d9d0fa..924f114af9 100644 --- a/src/Module/Api/Mastodon/Lists/Accounts.php +++ b/src/Module/Api/Mastodon/Lists/Accounts.php @@ -27,7 +27,7 @@ use Friendica\DI; use Friendica\Module\BaseApi; /** - * @see https://docs.joinmastodon.org/methods/timelines/lists/ + * @see https://docs.joinmastodon.org/methods/timelines/lists/#accounts-in-a-list * * Currently the output will be unordered since we use public contact ids in the api and not user contact ids. */ @@ -61,6 +61,8 @@ class Accounts extends BaseApi DI::mstdnError()->RecordNotFound(); } + // @todo provide HTTP link header + $request = self::getRequest([ 'max_id' => 0, // Return results older than this id 'since_id' => 0, // Return results newer than this id diff --git a/src/Module/Api/Mastodon/Mutes.php b/src/Module/Api/Mastodon/Mutes.php index f3aca86fa3..f0c225f188 100644 --- a/src/Module/Api/Mastodon/Mutes.php +++ b/src/Module/Api/Mastodon/Mutes.php @@ -49,6 +49,8 @@ class Mutes extends BaseApi DI::mstdnError()->RecordNotFound(); } + // @todo provide HTTP link header + $request = self::getRequest([ 'max_id' => 0, // Return results older than this id 'since_id' => 0, // Return results newer than this id diff --git a/src/Module/Api/Mastodon/Notifications.php b/src/Module/Api/Mastodon/Notifications.php index 6704e958f6..9a606c2aa7 100644 --- a/src/Module/Api/Mastodon/Notifications.php +++ b/src/Module/Api/Mastodon/Notifications.php @@ -57,7 +57,7 @@ class Notifications extends BaseApi 'limit' => 20, // Maximum number of results to return (default 20) 'exclude_types' => [], // Array of types to exclude (follow, favourite, reblog, mention, poll, follow_request) 'account_id' => 0, // Return only notifications received from this account - 'with_muted' => false, // Unknown parameter + 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. 'count' => 0, // Unknown parameter ]); diff --git a/src/Module/Api/Mastodon/Search.php b/src/Module/Api/Mastodon/Search.php index 592175149e..6bac5779ce 100644 --- a/src/Module/Api/Mastodon/Search.php +++ b/src/Module/Api/Mastodon/Search.php @@ -55,8 +55,8 @@ class Search extends BaseApi 'q' => '', // The search query 'resolve' => false, // Attempt WebFinger lookup. Defaults to false. 'limit' => 20, // Maximum number of results to load, per type. Defaults to 20. Max 40. - 'offset' => 0, // Maximum number of results to load, per type. Defaults to 20. Max 40. - 'following' => false, // Only who the user is following. Defaults to false. + 'offset' => 0, // Offset in search results. Used for pagination. Defaults to 0. + 'following' => false, // Only include accounts that the user is following. Defaults to false. ]); if (empty($request['q'])) { diff --git a/src/Module/Api/Mastodon/Suggestions.php b/src/Module/Api/Mastodon/Suggestions.php index df434d2dc5..27c64decda 100644 --- a/src/Module/Api/Mastodon/Suggestions.php +++ b/src/Module/Api/Mastodon/Suggestions.php @@ -40,10 +40,11 @@ class Suggestions extends BaseApi self::login(self::SCOPE_READ); $uid = self::getCurrentUserID(); - // Maximum number of results to return. Defaults to 40. - $limit = (int)!isset($_REQUEST['limit']) ? 40 : $_REQUEST['limit']; + $request = self::getRequest([ + 'limit' => 40, // Maximum number of results to return. Defaults to 40. + ]); - $suggestions = Contact\Relation::getSuggestions($uid, 0, $limit); + $suggestions = Contact\Relation::getSuggestions($uid, 0, $request['limit']); $accounts = []; diff --git a/src/Module/Api/Mastodon/Timelines/Home.php b/src/Module/Api/Mastodon/Timelines/Home.php index 07a5bc7e66..c4ca074f4b 100644 --- a/src/Module/Api/Mastodon/Timelines/Home.php +++ b/src/Module/Api/Mastodon/Timelines/Home.php @@ -47,8 +47,11 @@ class Home extends BaseApi 'since_id' => 0, // Return results newer than id 'min_id' => 0, // Return results immediately newer than id 'limit' => 20, // Maximum number of results to return. Defaults to 20. - 'local' => false, // Return only local statuses? Defaults to false. - 'with_muted' => false, // Unknown parameter + 'local' => false, // Return only local statuses? + 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. + 'only_media' => false, // Show only statuses with media attached? Defaults to false. + 'local' => false, // Show only local statuses? Defaults to false. + 'remote' => false, // Show only remote statuses? Defaults to false. ]); $params = ['order' => ['uri-id' => true], 'limit' => $request['limit']]; @@ -73,6 +76,19 @@ class Home extends BaseApi $params['order'] = ['uri-id']; } + if ($request['only_media']) { + $condition = DBA::mergeConditions($condition, ["`uri-id` IN (SELECT `uri-id` FROM `post-media` WHERE `type` IN (?, ?, ?))", + Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]); + } + + if ($request['local']) { + $condition = DBA::mergeConditions($condition, ["`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)"]); + } + + if ($request['remote']) { + $condition = DBA::mergeConditions($condition, ["NOT `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)"]); + } + $items = Post::selectForUser($uid, ['uri-id'], $condition, $params); $statuses = []; diff --git a/src/Module/Api/Mastodon/Timelines/ListTimeline.php b/src/Module/Api/Mastodon/Timelines/ListTimeline.php index f50c2d2aa7..0ff22cba4b 100644 --- a/src/Module/Api/Mastodon/Timelines/ListTimeline.php +++ b/src/Module/Api/Mastodon/Timelines/ListTimeline.php @@ -50,8 +50,11 @@ class ListTimeline extends BaseApi 'max_id' => 0, // Return results older than id 'since_id' => 0, // Return results newer than id 'min_id' => 0, // Return results immediately newer than id - 'limit' => 20, // Maximum number of results to return. Defaults to 20. - 'with_muted' => false, // Unknown parameter + 'limit' => 20, // Maximum number of results to return. Defaults to 20.Return results older than this ID. + 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. + 'only_media' => false, // Show only statuses with media attached? Defaults to false. + 'local' => false, // Show only local statuses? Defaults to false. + 'remote' => false, // Show only remote statuses? Defaults to false. ]); $params = ['order' => ['uri-id' => true], 'limit' => $request['limit']]; @@ -73,6 +76,19 @@ class ListTimeline extends BaseApi $params['order'] = ['uri-id']; } + if ($request['only_media']) { + $condition = DBA::mergeConditions($condition, ["`uri-id` IN (SELECT `uri-id` FROM `post-media` WHERE `type` IN (?, ?, ?))", + Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]); + } + + if ($request['local']) { + $condition = DBA::mergeConditions($condition, ["`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)"]); + } + + if ($request['remote']) { + $condition = DBA::mergeConditions($condition, ["NOT `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)"]); + } + $items = Post::selectForUser($uid, ['uri-id'], $condition, $params); $statuses = []; diff --git a/src/Module/Api/Mastodon/Timelines/PublicTimeline.php b/src/Module/Api/Mastodon/Timelines/PublicTimeline.php index fc52277784..05f3c7baf4 100644 --- a/src/Module/Api/Mastodon/Timelines/PublicTimeline.php +++ b/src/Module/Api/Mastodon/Timelines/PublicTimeline.php @@ -49,7 +49,7 @@ class PublicTimeline extends BaseApi 'since_id' => 0, // Return results newer than this id 'min_id' => 0, // Return results immediately newer than this id 'limit' => 20, // Maximum number of results to return. Defaults to 20. - 'with_muted' => false, // Unknown parameter + 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. ]); $params = ['order' => ['uri-id' => true], 'limit' => $request['limit']]; diff --git a/src/Module/Api/Mastodon/Timelines/Tag.php b/src/Module/Api/Mastodon/Timelines/Tag.php index b5d0d21401..e33923dfdb 100644 --- a/src/Module/Api/Mastodon/Timelines/Tag.php +++ b/src/Module/Api/Mastodon/Timelines/Tag.php @@ -47,44 +47,46 @@ class Tag extends BaseApi DI::mstdnError()->UnprocessableEntity(); } - // If true, return only local statuses. Defaults to false. - $local = (bool)!isset($_REQUEST['local']) ? false : ($_REQUEST['local'] == 'true'); - // If true, return only statuses with media attachments. Defaults to false. - $only_media = (bool)!isset($_REQUEST['only_media']) ? false : ($_REQUEST['only_media'] == 'true'); - // Return results older than this ID. - $max_id = (int)!isset($_REQUEST['max_id']) ? 0 : $_REQUEST['max_id']; - // Return results newer than this ID. - $since_id = (int)!isset($_REQUEST['since_id']) ? 0 : $_REQUEST['since_id']; - // Return results immediately newer than this ID. - $min_id = (int)!isset($_REQUEST['min_id']) ? 0 : $_REQUEST['min_id']; - // Maximum number of results to return. Defaults to 20. - $limit = (int)!isset($_REQUEST['limit']) ? 20 : $_REQUEST['limit']; + $request = self::getRequest([ + 'local' => false, // If true, return only local statuses. Defaults to false. + 'remote' => false, // Show only remote statuses? Defaults to false. + 'only_media' => false, // If true, return only statuses with media attachments. Defaults to false. + 'max_id' => 0, // Return results older than this ID. + 'since_id' => 0, // Return results newer than this ID. + 'min_id' => 0, // Return results immediately newer than this ID. + 'limit' => 20, // Maximum number of results to return. Defaults to 20. + 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. + ]); - $params = ['order' => ['uri-id' => true], 'limit' => $limit]; + $params = ['order' => ['uri-id' => true], 'limit' => $request['limit']]; $condition = ["`name` = ? AND (`uid` = ? OR (`uid` = ? AND NOT `global`)) AND (`network` IN (?, ?, ?, ?) OR (`uid` = ? AND `uid` != ?))", $parameters['hashtag'], 0, $uid, Protocol::ACTIVITYPUB, Protocol::DFRN, Protocol::DIASPORA, Protocol::OSTATUS, $uid, 0]; - if ($local) { + if ($request['local']) { $condition = DBA::mergeConditions($condition, ["`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)"]); } - if ($only_media) { + if ($request['remote']) { + $condition = DBA::mergeConditions($condition, ["NOT `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)"]); + } + + if ($request['only_media']) { $condition = DBA::mergeConditions($condition, ["`uri-id` IN (SELECT `uri-id` FROM `post-media` WHERE `type` IN (?, ?, ?))", Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]); } - if (!empty($max_id)) { - $condition = DBA::mergeConditions($condition, ["`uri-id` < ?", $max_id]); + if (!empty($request['max_id'])) { + $condition = DBA::mergeConditions($condition, ["`uri-id` < ?", $request['max_id']]); } - if (!empty($since_id)) { - $condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $since_id]); + if (!empty($request['since_id'])) { + $condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $request['since_id']]); } - if (!empty($min_id)) { - $condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $min_id]); + if (!empty($request['min_id'])) { + $condition = DBA::mergeConditions($condition, ["`uri-id` > ?", $request['min_id']]); $params['order'] = ['uri-id']; } @@ -97,7 +99,7 @@ class Tag extends BaseApi } DBA::close($items); - if (!empty($min_id)) { + if (!empty($request['min_id'])) { array_reverse($statuses); } diff --git a/src/Module/Api/Mastodon/Trends.php b/src/Module/Api/Mastodon/Trends.php index 0171db661b..7765a175a9 100644 --- a/src/Module/Api/Mastodon/Trends.php +++ b/src/Module/Api/Mastodon/Trends.php @@ -37,8 +37,9 @@ class Trends extends BaseApi */ public static function rawContent(array $parameters = []) { - // Maximum number of results to return. Defaults to 10. - $limit = (int)!isset($_REQUEST['limit']) ? 10 : $_REQUEST['limit']; + $request = self::getRequest([ + 'limit' => 20, // Maximum number of results to return. Defaults to 10. + ]); $trending = []; $tags = Tag::getGlobalTrendingHashtags(24, 20); @@ -48,6 +49,6 @@ class Trends extends BaseApi $trending[] = $hashtag->toArray(); } - System::jsonExit(array_slice($trending, 0, $limit)); + System::jsonExit(array_slice($trending, 0, $request['limit'])); } } diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index 3834c0cd5f..d5dc68932a 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -37,24 +37,26 @@ class Authorize extends BaseApi */ public static function rawContent(array $parameters = []) { - $response_type = $_REQUEST['response_type'] ?? ''; - $client_id = $_REQUEST['client_id'] ?? ''; - $client_secret = $_REQUEST['client_secret'] ?? ''; // Isn't normally provided. We will use it if present. - $redirect_uri = $_REQUEST['redirect_uri'] ?? ''; - $scope = $_REQUEST['scope'] ?? 'read'; - $state = $_REQUEST['state'] ?? ''; + $request = self::getRequest([ + 'response_type' => '', + 'client_id' => '', + 'client_secret' => '', // Isn't normally provided. We will use it if present. + 'redirect_uri' => '', + 'scope' => 'read', + 'state' => '', + ]); - if ($response_type != 'code') { + if ($request['response_type'] != 'code') { Logger::warning('Unsupported or missing response type', ['request' => $_REQUEST]); DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Unsupported or missing response type')); } - if (empty($client_id) || empty($redirect_uri)) { + if (empty($request['client_id']) || empty($request['redirect_uri'])) { Logger::warning('Incomplete request data', ['request' => $_REQUEST]); DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Incomplete request data')); } - $application = self::getApplication($client_id, $client_secret, $redirect_uri); + $application = self::getApplication($request['client_id'], $request['client_secret'], $request['redirect_uri']); if (empty($application)) { DI::mstdnError()->UnprocessableEntity(); } @@ -80,11 +82,11 @@ class Authorize extends BaseApi DI::session()->remove('oauth_acknowledge'); - $token = self::createTokenForUser($application, $uid, $scope); + $token = self::createTokenForUser($application, $uid, $request['scope']); if (!$token) { DI::mstdnError()->UnprocessableEntity(); } - DI::app()->redirect($application['redirect_uri'] . (strpos($application['redirect_uri'], '?') ? '&' : '?') . http_build_query(['code' => $token['code'], 'state' => $state])); + DI::app()->redirect($application['redirect_uri'] . (strpos($application['redirect_uri'], '?') ? '&' : '?') . http_build_query(['code' => $token['code'], 'state' => $request['state']])); } } diff --git a/src/Module/OAuth/Token.php b/src/Module/OAuth/Token.php index c7a8109698..780fc7cea6 100644 --- a/src/Module/OAuth/Token.php +++ b/src/Module/OAuth/Token.php @@ -35,39 +35,41 @@ class Token extends BaseApi { public static function post(array $parameters = []) { - $grant_type = $_REQUEST['grant_type'] ?? ''; - $code = $_REQUEST['code'] ?? ''; - $redirect_uri = $_REQUEST['redirect_uri'] ?? ''; - $client_id = $_REQUEST['client_id'] ?? ''; - $client_secret = $_REQUEST['client_secret'] ?? ''; + $request = self::getRequest([ + 'grant_type' => '', + 'code' => '', + 'redirect_uri' => '', + 'client_id' => '', + 'client_secret' => '', + ]); // AndStatus transmits the client data in the AUTHORIZATION header field, see https://github.com/andstatus/andstatus/issues/530 - if (empty($client_id) && !empty($_SERVER['HTTP_AUTHORIZATION']) && (substr($_SERVER['HTTP_AUTHORIZATION'], 0, 6) == 'Basic ')) { + if (empty($request['client_id']) && !empty($_SERVER['HTTP_AUTHORIZATION']) && (substr($_SERVER['HTTP_AUTHORIZATION'], 0, 6) == 'Basic ')) { $datapair = explode(':', base64_decode(trim(substr($_SERVER['HTTP_AUTHORIZATION'], 6)))); if (count($datapair) == 2) { - $client_id = $datapair[0]; - $client_secret = $datapair[1]; + $request['client_id'] = $datapair[0]; + $request['client_secret'] = $datapair[1]; } } - if (empty($client_id) || empty($client_secret)) { + if (empty($request['client_id']) || empty($request['client_secret'])) { Logger::warning('Incomplete request data', ['request' => $_REQUEST]); DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Incomplete request data')); } - $application = self::getApplication($client_id, $client_secret, $redirect_uri); + $application = self::getApplication($request['client_id'], $request['client_secret'], $request['redirect_uri']); if (empty($application)) { DI::mstdnError()->UnprocessableEntity(); } - if ($grant_type == 'client_credentials') { + if ($request['grant_type'] == 'client_credentials') { // the "client_credentials" are used as a token for the application itself. // see https://aaronparecki.com/oauth-2-simplified/#client-credentials $token = self::createTokenForUser($application, 0, ''); - } elseif ($grant_type == 'authorization_code') { + } elseif ($request['grant_type'] == 'authorization_code') { // For security reasons only allow freshly created tokens $condition = ["`redirect_uri` = ? AND `id` = ? AND `code` = ? AND `created_at` > UTC_TIMESTAMP() - INTERVAL ? MINUTE", - $redirect_uri, $application['id'], $code, 5]; + $request['redirect_uri'], $application['id'], $request['code'], 5]; $token = DBA::selectFirst('application-view', ['access_token', 'created_at'], $condition); if (!DBA::isResult($token)) { From 50ca38a0f76dab0919825278a39805af3338aa5a Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 19 May 2021 06:55:08 +0000 Subject: [PATCH 2/4] Harmonized API parameters for all timeline endpoints --- src/Module/Api/Mastodon/Timelines/Home.php | 26 +++++++++---------- .../Api/Mastodon/Timelines/ListTimeline.php | 21 +++++++++------ .../Api/Mastodon/Timelines/PublicTimeline.php | 21 +++++++++------ src/Module/Api/Mastodon/Timelines/Tag.php | 21 +++++++++------ 4 files changed, 52 insertions(+), 37 deletions(-) diff --git a/src/Module/Api/Mastodon/Timelines/Home.php b/src/Module/Api/Mastodon/Timelines/Home.php index c4ca074f4b..0c955b1c7e 100644 --- a/src/Module/Api/Mastodon/Timelines/Home.php +++ b/src/Module/Api/Mastodon/Timelines/Home.php @@ -43,15 +43,15 @@ class Home extends BaseApi $uid = self::getCurrentUserID(); $request = self::getRequest([ - 'max_id' => 0, // Return results older than id - 'since_id' => 0, // Return results newer than id - 'min_id' => 0, // Return results immediately newer than id - 'limit' => 20, // Maximum number of results to return. Defaults to 20. - 'local' => false, // Return only local statuses? - 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. - 'only_media' => false, // Show only statuses with media attached? Defaults to false. - 'local' => false, // Show only local statuses? Defaults to false. - 'remote' => false, // Show only remote statuses? Defaults to false. + 'max_id' => 0, // Return results older than id + 'since_id' => 0, // Return results newer than id + 'min_id' => 0, // Return results immediately newer than id + 'limit' => 20, // Maximum number of results to return. Defaults to 20. + 'local' => false, // Return only local statuses? + 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. + 'only_media' => false, // Show only statuses with media attached? Defaults to false. + 'remote' => false, // Show only remote statuses? Defaults to false. + 'exclude_replies' => false, // Don't show comments ]); $params = ['order' => ['uri-id' => true], 'limit' => $request['limit']]; @@ -81,14 +81,14 @@ class Home extends BaseApi Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]); } - if ($request['local']) { - $condition = DBA::mergeConditions($condition, ["`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)"]); - } - if ($request['remote']) { $condition = DBA::mergeConditions($condition, ["NOT `uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)"]); } + if ($request['exclude_replies']) { + $condition = DBA::mergeConditions($condition, ['gravity' => GRAVITY_PARENT]); + } + $items = Post::selectForUser($uid, ['uri-id'], $condition, $params); $statuses = []; diff --git a/src/Module/Api/Mastodon/Timelines/ListTimeline.php b/src/Module/Api/Mastodon/Timelines/ListTimeline.php index 0ff22cba4b..e5bf9d76f1 100644 --- a/src/Module/Api/Mastodon/Timelines/ListTimeline.php +++ b/src/Module/Api/Mastodon/Timelines/ListTimeline.php @@ -47,14 +47,15 @@ class ListTimeline extends BaseApi } $request = self::getRequest([ - 'max_id' => 0, // Return results older than id - 'since_id' => 0, // Return results newer than id - 'min_id' => 0, // Return results immediately newer than id - 'limit' => 20, // Maximum number of results to return. Defaults to 20.Return results older than this ID. - 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. - 'only_media' => false, // Show only statuses with media attached? Defaults to false. - 'local' => false, // Show only local statuses? Defaults to false. - 'remote' => false, // Show only remote statuses? Defaults to false. + 'max_id' => 0, // Return results older than id + 'since_id' => 0, // Return results newer than id + 'min_id' => 0, // Return results immediately newer than id + 'limit' => 20, // Maximum number of results to return. Defaults to 20.Return results older than this ID. + 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. + 'only_media' => false, // Show only statuses with media attached? Defaults to false. + 'local' => false, // Show only local statuses? Defaults to false. + 'remote' => false, // Show only remote statuses? Defaults to false. + 'exclude_replies' => false, // Don't show comments ]); $params = ['order' => ['uri-id' => true], 'limit' => $request['limit']]; @@ -81,6 +82,10 @@ class ListTimeline extends BaseApi Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]); } + if ($request['exclude_replies']) { + $condition = DBA::mergeConditions($condition, ['gravity' => GRAVITY_PARENT]); + } + if ($request['local']) { $condition = DBA::mergeConditions($condition, ["`uri-id` IN (SELECT `uri-id` FROM `post-user` WHERE `origin`)"]); } diff --git a/src/Module/Api/Mastodon/Timelines/PublicTimeline.php b/src/Module/Api/Mastodon/Timelines/PublicTimeline.php index 05f3c7baf4..87d0dc1d96 100644 --- a/src/Module/Api/Mastodon/Timelines/PublicTimeline.php +++ b/src/Module/Api/Mastodon/Timelines/PublicTimeline.php @@ -42,14 +42,15 @@ class PublicTimeline extends BaseApi public static function rawContent(array $parameters = []) { $request = self::getRequest([ - 'local' => false, // Show only local statuses? Defaults to false. - 'remote' => false, // Show only remote statuses? Defaults to false. - 'only_media' => false, // Show only statuses with media attached? Defaults to false. - 'max_id' => 0, // Return results older than this id - 'since_id' => 0, // Return results newer than this id - 'min_id' => 0, // Return results immediately newer than this id - 'limit' => 20, // Maximum number of results to return. Defaults to 20. - 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. + 'local' => false, // Show only local statuses? Defaults to false. + 'remote' => false, // Show only remote statuses? Defaults to false. + 'only_media' => false, // Show only statuses with media attached? Defaults to false. + 'max_id' => 0, // Return results older than this id + 'since_id' => 0, // Return results newer than this id + 'min_id' => 0, // Return results immediately newer than this id + 'limit' => 20, // Maximum number of results to return. Defaults to 20. + 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. + 'exclude_replies' => false, // Don't show comments ]); $params = ['order' => ['uri-id' => true], 'limit' => $request['limit']]; @@ -83,6 +84,10 @@ class PublicTimeline extends BaseApi $params['order'] = ['uri-id']; } + if ($request['exclude_replies']) { + $condition = DBA::mergeConditions($condition, ['gravity' => GRAVITY_PARENT]); + } + $items = Post::selectForUser(0, ['uri-id', 'uid'], $condition, $params); $statuses = []; diff --git a/src/Module/Api/Mastodon/Timelines/Tag.php b/src/Module/Api/Mastodon/Timelines/Tag.php index e33923dfdb..efcab825ad 100644 --- a/src/Module/Api/Mastodon/Timelines/Tag.php +++ b/src/Module/Api/Mastodon/Timelines/Tag.php @@ -48,14 +48,15 @@ class Tag extends BaseApi } $request = self::getRequest([ - 'local' => false, // If true, return only local statuses. Defaults to false. - 'remote' => false, // Show only remote statuses? Defaults to false. - 'only_media' => false, // If true, return only statuses with media attachments. Defaults to false. - 'max_id' => 0, // Return results older than this ID. - 'since_id' => 0, // Return results newer than this ID. - 'min_id' => 0, // Return results immediately newer than this ID. - 'limit' => 20, // Maximum number of results to return. Defaults to 20. - 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. + 'local' => false, // If true, return only local statuses. Defaults to false. + 'remote' => false, // Show only remote statuses? Defaults to false. + 'only_media' => false, // If true, return only statuses with media attachments. Defaults to false. + 'max_id' => 0, // Return results older than this ID. + 'since_id' => 0, // Return results newer than this ID. + 'min_id' => 0, // Return results immediately newer than this ID. + 'limit' => 20, // Maximum number of results to return. Defaults to 20. + 'with_muted' => false, // Pleroma extension: return activities by muted (not by blocked!) users. + 'exclude_replies' => false, // Don't show comments ]); $params = ['order' => ['uri-id' => true], 'limit' => $request['limit']]; @@ -77,6 +78,10 @@ class Tag extends BaseApi Post\Media::AUDIO, Post\Media::IMAGE, Post\Media::VIDEO]); } + if ($request['exclude_replies']) { + $condition = DBA::mergeConditions($condition, ['gravity' => GRAVITY_PARENT]); + } + if (!empty($request['max_id'])) { $condition = DBA::mergeConditions($condition, ["`uri-id` < ?", $request['max_id']]); } From b3b9c51dbe3ea3cf3401418c5db9f7818c1702a7 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 19 May 2021 07:02:12 +0000 Subject: [PATCH 3/4] Reduced log level --- src/Module/BaseApi.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/BaseApi.php b/src/Module/BaseApi.php index c12872104b..e0b1da01b4 100644 --- a/src/Module/BaseApi.php +++ b/src/Module/BaseApi.php @@ -315,7 +315,7 @@ class BaseApi extends BaseModule Logger::warning('Token not found', $condition); return []; } - Logger::info('Token found', $token); + Logger::debug('Token found', $token); return $token; } From 3172b0bcf28fb8f602e27df7f2aa77ec26f3233b Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 19 May 2021 09:03:41 +0000 Subject: [PATCH 4/4] Log API errors --- src/Factory/Api/Mastodon/Error.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/Factory/Api/Mastodon/Error.php b/src/Factory/Api/Mastodon/Error.php index 4ec8744bff..31f719307e 100644 --- a/src/Factory/Api/Mastodon/Error.php +++ b/src/Factory/Api/Mastodon/Error.php @@ -22,17 +22,24 @@ namespace Friendica\Factory\Api\Mastodon; use Friendica\BaseFactory; +use Friendica\Core\Logger; use Friendica\Core\System; use Friendica\DI; class Error extends BaseFactory { + private function logError(int $errorno, string $error) + { + Logger::info('API Error', ['no' => $errorno, 'error' => $error, 'method' => $_SERVER['REQUEST_METHOD'] ?? '', 'command' => DI::args()->getQueryString(), 'user-agent' => $_SERVER['HTTP_USER_AGENT'] ?? '']); + } + public function RecordNotFound() { $error = DI::l10n()->t('Record not found'); $error_description = ''; $errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description); + $this->logError(404, $error); System::jsonError(404, $errorobj->toArray()); } @@ -42,6 +49,7 @@ class Error extends BaseFactory $error_description = ''; $errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description); + $this->logError(422, $error); System::jsonError(422, $errorobj->toArray()); } @@ -51,6 +59,7 @@ class Error extends BaseFactory $error_description = ''; $errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description); + $this->logError(401, $error); System::jsonError(401, $errorobj->toArray()); } @@ -60,6 +69,7 @@ class Error extends BaseFactory $error_description = ''; $errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description); + $this->logError(403, $error); System::jsonError(403, $errorobj->toArray()); } @@ -69,6 +79,7 @@ class Error extends BaseFactory $error_description = ''; $errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description); + $this->logError(500, $error); System::jsonError(500, $errorobj->toArray()); } }