From bade0a2345e977854f906529960c55a35a3197da Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 11 May 2021 19:15:05 +0000 Subject: [PATCH 01/22] Improved cards handling, simplified Bearer handling --- src/DI.php | 8 +++ src/Factory/Api/Mastodon/Card.php | 78 +++++++++++++++++++++++++++++ src/Factory/Api/Mastodon/Status.php | 9 ++-- src/Model/Item.php | 2 +- src/Module/BaseApi.php | 36 ++++++------- src/Object/Api/Mastodon/Card.php | 14 +++++- src/Object/Api/Mastodon/Status.php | 2 +- 7 files changed, 120 insertions(+), 29 deletions(-) create mode 100644 src/Factory/Api/Mastodon/Card.php diff --git a/src/DI.php b/src/DI.php index 37091a5ab..9e77943bd 100644 --- a/src/DI.php +++ b/src/DI.php @@ -255,6 +255,14 @@ abstract class DI return self::$dice->create(Factory\Api\Mastodon\Attachment::class); } + /** + * @return Factory\Api\Mastodon\Card + */ + public static function mstdnCard() + { + return self::$dice->create(Factory\Api\Mastodon\Card::class); + } + /** * @return Factory\Api\Mastodon\Emoji */ diff --git a/src/Factory/Api/Mastodon/Card.php b/src/Factory/Api/Mastodon/Card.php new file mode 100644 index 000000000..cc160b102 --- /dev/null +++ b/src/Factory/Api/Mastodon/Card.php @@ -0,0 +1,78 @@ +. + * + */ + +namespace Friendica\Factory\Api\Mastodon; + +use Friendica\BaseFactory; +use Friendica\Content\Text\BBCode; +use Friendica\Model\Post; +use Friendica\Network\HTTPException; +use Friendica\Util\Strings; + +class Card extends BaseFactory +{ + /** + * @param int $uriId Uri-ID of the item + * @return \Friendica\Object\Api\Mastodon\Card + * @throws HTTPException\InternalServerErrorException + * @throws \ImagickException + */ + public function createFromUriId(int $uriId) + { + $item = Post::selectFirst(['nody'], ['uri-id' => $uriId]); + if (!empty($item['body'])) { + $data = BBCode::getAttachmentData($item['body']); + } + + foreach (Post\Media::getByURIId($uriId, [Post\Media::HTML]) as $attached) { + if ((empty($data['url']) || Strings::compareLink($data['url'], $attached['url'])) && + (!empty($attached['description']) || !empty($attached['image']) || !empty($attached['preview']))) { + $parts = parse_url($attached['url']); + if (!empty($parts['scheme']) && !empty($parts['host'])) { + if (empty($attached['publisher-name'])) { + $attached['publisher-name'] = $parts['host']; + } + if (empty($attached['publisher-url']) || empty(parse_url($attached['publisher-url'], PHP_URL_SCHEME))) { + $attached['publisher-url'] = $parts['scheme'] . '://' . $parts['host']; + + if (!empty($parts['port'])) { + $attached['publisher-url'] .= ':' . $parts['port']; + } + } + } + + $data['url'] = $attached['url']; + $data['title'] = $attached['name']; + $data['description'] = $attached['description']; + $data['type'] = 'link'; + $data['author_name'] = $attached['author-name']; + $data['author_url'] = $attached['author-url']; + $data['provider_name'] = $attached['publisher-name']; + $data['provider_url'] = $attached['publisher-url']; + $data['image'] = $attached['preview']; + $data['width'] = $attached['preview-width']; + $data['height'] = $attached['preview-height']; + } + } + + return new \Friendica\Object\Api\Mastodon\Card($data); + } +} diff --git a/src/Factory/Api/Mastodon/Status.php b/src/Factory/Api/Mastodon/Status.php index 310fa26bb..c26b9aa72 100644 --- a/src/Factory/Api/Mastodon/Status.php +++ b/src/Factory/Api/Mastodon/Status.php @@ -24,7 +24,6 @@ namespace Friendica\Factory\Api\Mastodon; use Friendica\App\BaseURL; use Friendica\BaseFactory; use Friendica\Content\ContactSelector; -use Friendica\Content\Text\BBCode; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Post; @@ -86,12 +85,10 @@ class Status extends BaseFactory $sensitive = DBA::exists('tag-view', ['uri-id' => $uriId, 'name' => 'nsfw']); $application = new \Friendica\Object\Api\Mastodon\Application($item['app'] ?: ContactSelector::networkToName($item['network'], $item['author-link'])); - $mentions = DI::mstdnMention()->createFromUriId($uriId); - $tags = DI::mstdnTag()->createFromUriId($uriId); - - $data = BBCode::getAttachmentData($item['body']); - $card = new \Friendica\Object\Api\Mastodon\Card($data); + $mentions = DI::mstdnMention()->createFromUriId($uriId); + $tags = DI::mstdnTag()->createFromUriId($uriId); + $card = DI::mstdnCard()->createFromUriId($uriId); $attachments = DI::mstdnAttachment()->createFromUriId($uriId); if ($item['vid'] == Verb::getID(Activity::ANNOUNCE)) { diff --git a/src/Model/Item.php b/src/Model/Item.php index ab99e8c1a..e0e4561ae 100644 --- a/src/Model/Item.php +++ b/src/Model/Item.php @@ -2927,7 +2927,7 @@ class Item DI::profiler()->saveTimestamp($stamp1, 'rendering'); if (isset($data['url']) && !in_array($data['url'], $ignore_links)) { - if (!empty($data['description']) || !empty($data['image'] || !empty($data['preview']))) { + if (!empty($data['description']) || !empty($data['image']) || !empty($data['preview'])) { $parts = parse_url($data['url']); if (!empty($parts['scheme']) && !empty($parts['host'])) { if (empty($data['provider_name'])) { diff --git a/src/Module/BaseApi.php b/src/Module/BaseApi.php index f79832026..bd42e373d 100644 --- a/src/Module/BaseApi.php +++ b/src/Module/BaseApi.php @@ -138,15 +138,13 @@ class BaseApi extends BaseModule */ protected static function login() { - $authorization = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; - $authorization = $_SERVER['AUTHORIZATION'] ?? $authorization; - - if (self::checkBearer($authorization)) { - self::$current_user_id = self::getUserByBearer($authorization); - return (bool)self::$current_user_id; + if (empty(self::$current_user_id)) { + self::$current_user_id = self::getUserByBearer(); } - api_login(DI::app()); + if (empty(self::$current_user_id)) { + api_login(DI::app()); + } self::$current_user_id = api_user(); @@ -160,15 +158,11 @@ class BaseApi extends BaseModule */ protected static function getCurrentUserID() { - $authorization = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; - $authorization = $_SERVER['AUTHORIZATION'] ?? $authorization; - - if (self::checkBearer($authorization)) { - self::$current_user_id = self::getUserByBearer($authorization); - return (int)self::$current_user_id; + if (empty(self::$current_user_id)) { + self::$current_user_id = self::getUserByBearer(); } - if (is_null(self::$current_user_id)) { + if (empty(self::$current_user_id)) { api_login(DI::app(), false); self::$current_user_id = api_user(); @@ -177,14 +171,16 @@ class BaseApi extends BaseModule return (int)self::$current_user_id; } - private static function checkBearer(string $authorization) + private static function getUserByBearer() { - return (substr($authorization, 0, 7) == 'Bearer '); - } + $authorization = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; + $authorization = $_SERVER['AUTHORIZATION'] ?? $authorization; - private static function getUserByBearer(string $authorization) - { - $bearer = trim(substr($authorization, 6)); + if (substr($authorization, 0, 7) != 'Bearer ') { + return 0; + } + + $bearer = trim(substr($authorization, 7)); $condition = ['access_token' => $bearer]; $token = DBA::selectFirst('application-token', ['uid'], $condition); if (!DBA::isResult($token)) { diff --git a/src/Object/Api/Mastodon/Card.php b/src/Object/Api/Mastodon/Card.php index 6abf58fdc..b18ba28e4 100644 --- a/src/Object/Api/Mastodon/Card.php +++ b/src/Object/Api/Mastodon/Card.php @@ -39,9 +39,17 @@ class Card extends BaseDataTransferObject /** @var string */ protected $type; /** @var string */ + protected $author_name; + /** @var string */ + protected $author_url; + /** @var string */ protected $provider_name; /** @var string */ protected $provider_url; + /** @var int */ + protected $width; + /** @var int */ + protected $height; /** @var string */ protected $image; @@ -57,9 +65,13 @@ class Card extends BaseDataTransferObject $this->title = $attachment['title'] ?? ''; $this->description = $attachment['description'] ?? ''; $this->type = $attachment['type'] ?? ''; - $this->image = $attachment['image'] ?? ''; + $this->author_name = $attachment['author_name'] ?? ''; + $this->author_url = $attachment['author_url'] ?? ''; $this->provider_name = $attachment['provider_name'] ?? ''; $this->provider_url = $attachment['provider_url'] ?? ''; + $this->width = $attachment['width'] ?? 0; + $this->height = $attachment['height'] ?? 0; + $this->image = $attachment['image'] ?? ''; } /** diff --git a/src/Object/Api/Mastodon/Status.php b/src/Object/Api/Mastodon/Status.php index 26c0705bd..227395d17 100644 --- a/src/Object/Api/Mastodon/Status.php +++ b/src/Object/Api/Mastodon/Status.php @@ -134,7 +134,7 @@ class Status extends BaseDataTransferObject $this->mentions = $mentions; $this->tags = $tags; $this->emojis = []; - //$this->card = $card; + $this->card = $card->toArray() ?: null; $this->poll = null; } From 8eacfbc5705410ebd098a5bd790c7b7355ab65fc Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 11 May 2021 19:53:19 +0000 Subject: [PATCH 02/22] Fix context order / notice fixed --- src/Factory/Api/Mastodon/Card.php | 2 ++ src/Module/Api/Mastodon/Statuses/Context.php | 19 ++++++++++++++++--- src/Module/OAuth/Token.php | 2 +- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Factory/Api/Mastodon/Card.php b/src/Factory/Api/Mastodon/Card.php index cc160b102..1505fa852 100644 --- a/src/Factory/Api/Mastodon/Card.php +++ b/src/Factory/Api/Mastodon/Card.php @@ -40,6 +40,8 @@ class Card extends BaseFactory $item = Post::selectFirst(['nody'], ['uri-id' => $uriId]); if (!empty($item['body'])) { $data = BBCode::getAttachmentData($item['body']); + } else { + $data = []; } foreach (Post\Media::getByURIId($uriId, [Post\Media::HTML]) as $attached) { diff --git a/src/Module/Api/Mastodon/Statuses/Context.php b/src/Module/Api/Mastodon/Statuses/Context.php index bf49d265c..5615e41cc 100644 --- a/src/Module/Api/Mastodon/Statuses/Context.php +++ b/src/Module/Api/Mastodon/Statuses/Context.php @@ -54,7 +54,8 @@ class Context extends BaseApi $parents = []; $children = []; - $posts = Post::select(['uri-id', 'thr-parent-id'], ['parent-uri-id' => $parent['parent-uri-id']], [], false); + $posts = Post::select(['uri-id', 'thr-parent-id'], + ['parent-uri-id' => $parent['parent-uri-id'], 'gravity' => [GRAVITY_PARENT, GRAVITY_COMMENT]], [], false); while ($post = Post::fetch($posts)) { if ($post['uri-id'] == $post['thr-parent-id']) { continue; @@ -67,12 +68,24 @@ class Context extends BaseApi $statuses = ['ancestors' => [], 'descendants' => []]; + $ancestors = []; foreach (self::getParents($id, $parents) as $ancestor) { - $statuses['ancestors'][] = DI::mstdnStatus()->createFromUriId($ancestor, $uid); + $ancestors[$ancestor] = DI::mstdnStatus()->createFromUriId($ancestor, $uid); } + ksort($ancestors); + foreach ($ancestors as $ancestor) { + $statuses['ancestors'][] = $ancestor; + } + + $descendants = []; foreach (self::getChildren($id, $children) as $descendant) { - $statuses['descendants'][] = DI::mstdnStatus()->createFromUriId($descendant, $uid); + $descendants[] = DI::mstdnStatus()->createFromUriId($descendant, $uid); + } + + ksort($descendants); + foreach ($descendants as $descendant) { + $statuses['descendants'][] = $descendant; } System::jsonExit($statuses); diff --git a/src/Module/OAuth/Token.php b/src/Module/OAuth/Token.php index 6e574a8af..1d0b43cd6 100644 --- a/src/Module/OAuth/Token.php +++ b/src/Module/OAuth/Token.php @@ -55,7 +55,7 @@ class Token extends BaseApi $condition = ['application-id' => $application['id'], 'code' => $code]; - $token = DBA::selectFirst('application-token', ['access_token'], $condition); + $token = DBA::selectFirst('application-token', ['access_token', 'created_at'], $condition); if (!DBA::isResult($token)) { Logger::warning('Token not found', $condition); DI::mstdnError()->RecordNotFound(); From 43244a3588534eb4c3e95f956c464e697dc10e83 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 11 May 2021 20:49:36 +0000 Subject: [PATCH 03/22] Fix top border on mobile login --- view/theme/frio/css/style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index a06d794f5..758207d15 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -3416,6 +3416,7 @@ section .profile-match-wrapper { .mod-home.is-not-singleuser nav.navbar, .mod-login nav.navbar { background-color: transparent; + position: inherit; } .mod-home.is-not-singleuser #topbar-second, .mod-login #topbar-second { From f5e98c8ecf8674c0f7f934574fb70cd583bb8c89 Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 11 May 2021 21:04:45 +0000 Subject: [PATCH 04/22] Redirect at login does work --- src/Module/OAuth/Authorize.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index c2e8cc30a..b091413bc 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -36,8 +36,6 @@ class Authorize extends BaseApi */ public static function rawContent(array $parameters = []) { - //return; - $response_type = !isset($_REQUEST['response_type']) ? '' : $_REQUEST['response_type']; if ($response_type != 'code') { Logger::warning('Wrong or missing response type', ['response_type' => $response_type]); @@ -52,7 +50,9 @@ class Authorize extends BaseApi $uid = local_user(); if (empty($uid)) { Logger::info('Redirect to login'); - DI::app()->redirect('login?return_path=/oauth/authorize'); + $request = $_REQUEST; + unset($request['pagename']); + DI::app()->redirect('login?return_path=/oauth/authorize' . urlencode('?' . http_build_query($request))); } else { Logger::info('Already logged in user', ['uid' => $uid]); } From 975c32116dc26034e6ec7562a30c398c329d3f9d Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 11 May 2021 23:10:59 +0000 Subject: [PATCH 05/22] Handling media in shared posts --- src/Factory/Api/Mastodon/Status.php | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/Factory/Api/Mastodon/Status.php b/src/Factory/Api/Mastodon/Status.php index c26b9aa72..866cfe802 100644 --- a/src/Factory/Api/Mastodon/Status.php +++ b/src/Factory/Api/Mastodon/Status.php @@ -24,6 +24,7 @@ namespace Friendica\Factory\Api\Mastodon; use Friendica\App\BaseURL; use Friendica\BaseFactory; use Friendica\Content\ContactSelector; +use Friendica\Content\Text\BBCode; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Model\Post; @@ -91,6 +92,22 @@ class Status extends BaseFactory $card = DI::mstdnCard()->createFromUriId($uriId); $attachments = DI::mstdnAttachment()->createFromUriId($uriId); + $shared = BBCode::fetchShareAttributes($item['body']); + if (!empty($shared['guid'])) { + $shared_item = Post::selectFirst(['uri-id', 'plink'], ['guid' => $shared['guid']]); + + $shared_uri_id = $shared_item['uri-id'] ?? 0; + + $mentions = array_merge($mentions, DI::mstdnMention()->createFromUriId($shared_uri_id)); + $tags = array_merge($tags, DI::mstdnTag()->createFromUriId($shared_uri_id)); + $attachments = array_merge($attachments, DI::mstdnAttachment()->createFromUriId($shared_uri_id)); + + if (empty($card->toArray())) { + $card = DI::mstdnCard()->createFromUriId($shared_uri_id); + } + } + + if ($item['vid'] == Verb::getID(Activity::ANNOUNCE)) { $reshare = $this->createFromUriId($item['thr-parent-id'], $uid)->toArray(); $reshared_item = Post::selectFirst(['title', 'body'], ['uri-id' => $item['thr-parent-id'], 'uid' => [0, $uid]]); From 4476634f6cecbfe7abb2207fe3ac83fdaa7a7aad Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 11 May 2021 23:39:08 +0000 Subject: [PATCH 06/22] Fix list of accounts --- src/Model/Post/Media.php | 16 ++++++++++++---- src/Module/Api/Mastodon/Lists/Accounts.php | 12 ++++++++++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/Model/Post/Media.php b/src/Model/Post/Media.php index 6f78b0905..c3f745fee 100644 --- a/src/Model/Post/Media.php +++ b/src/Model/Post/Media.php @@ -288,9 +288,13 @@ class Media public static function insertFromBody(int $uriid, string $body) { // Simplify image codes - $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); + $unshared_body = $body = preg_replace("/\[img\=([0-9]*)x([0-9]*)\](.*?)\[\/img\]/ism", '[img]$3[/img]', $body); - $unshared_body = preg_replace("/\s*\[share .*?\].*?\[\/share\]\s*/ism", '', $body); + // Only remove the shared data from "real" reshares + $shared = BBCode::fetchShareAttributes($body); + if (!empty($shared['guid'])) { + $unshared_body = preg_replace("/\s*\[share .*?\].*?\[\/share\]\s*/ism", '', $body); + } $attachments = []; if (preg_match_all("#\[url=([^\]]+?)\]\s*\[img=([^\[\]]*)\]([^\[\]]*)\[\/img\]\s*\[/url\]#ism", $body, $pictures, PREG_SET_ORDER)) { @@ -363,8 +367,12 @@ class Media */ public static function insertFromRelevantUrl(int $uriid, string $body) { - // Don't look at the shared content - $body = preg_replace("/\s*\[share .*?\].*?\[\/share\]\s*/ism", '', $body); + // Only remove the shared data from "real" reshares + $shared = BBCode::fetchShareAttributes($body); + if (!empty($shared['guid'])) { + // Don't look at the shared content + $body = preg_replace("/\s*\[share .*?\].*?\[\/share\]\s*/ism", '', $body); + } // Remove all hashtags and mentions $body = preg_replace("/([#@!])\[url\=(.*?)\](.*?)\[\/url\]/ism", '', $body); diff --git a/src/Module/Api/Mastodon/Lists/Accounts.php b/src/Module/Api/Mastodon/Lists/Accounts.php index 0b817cfc8..513ca21d7 100644 --- a/src/Module/Api/Mastodon/Lists/Accounts.php +++ b/src/Module/Api/Mastodon/Lists/Accounts.php @@ -65,12 +65,18 @@ class Accounts extends BaseApi $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']; - // Maximum number of results to return. Defaults to 20. + // Maximum number of results. Defaults to 40. Max 40. + // Set to 0 in order to get all accounts without pagination. $limit = (int)!isset($_REQUEST['limit']) ? 40 : $_REQUEST['limit']; - $params = ['order' => ['contact-id' => true], 'limit' => $limit]; + $params = ['order' => ['contact-id' => true]]; + if ($limit != 0) { + $params['limit'] = $limit; + + } + $condition = ['gid' => $id]; if (!empty($max_id)) { @@ -87,6 +93,8 @@ class Accounts extends BaseApi $params['order'] = ['contact-id']; } + $accounts = []; + $members = DBA::select('group_member', ['contact-id'], $condition, $params); while ($member = DBA::fetch($members)) { $accounts[] = DI::mstdnAccount()->createFromContactId($member['contact-id'], $uid); From e99117ac221a65137c2fc569c39e389d5cdc38cd Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Wed, 12 May 2021 03:53:40 +0200 Subject: [PATCH 07/22] Update src/Module/OAuth/Authorize.php Co-authored-by: Hypolite Petovan --- src/Module/OAuth/Authorize.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index b091413bc..8afc7d48a 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -52,7 +52,7 @@ class Authorize extends BaseApi Logger::info('Redirect to login'); $request = $_REQUEST; unset($request['pagename']); - DI::app()->redirect('login?return_path=/oauth/authorize' . urlencode('?' . http_build_query($request))); + DI::app()->redirect('login?return_path=' . urlencode('/oauth/authorize?' . http_build_query($request))); } else { Logger::info('Already logged in user', ['uid' => $uid]); } From d1e109d9beda95fa0e043f3e4e9f19cfaa4ad42f Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 03:05:22 +0000 Subject: [PATCH 08/22] Improved error handling --- src/Factory/Api/Mastodon/Error.php | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/Factory/Api/Mastodon/Error.php b/src/Factory/Api/Mastodon/Error.php index 2c3662288..086cceef9 100644 --- a/src/Factory/Api/Mastodon/Error.php +++ b/src/Factory/Api/Mastodon/Error.php @@ -35,4 +35,31 @@ class Error extends BaseFactory System::jsonError(404, $errorobj->toArray()); } + + public function UnprocessableEntity(string $error = '') + { + $error = $error ?: DI::l10n()->t('Unprocessable Entity'); + $error_description = ''; + $errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description); + + System::jsonError(422, $errorobj->toArray()); + } + + public function Unauthorized(string $error = '') + { + $error = $error ?: DI::l10n()->t('Unauthorized'); + $error_description = ''; + $errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description); + + System::jsonError(401, $errorobj->toArray()); + } + + public function InternalError(string $error = '') + { + $error = $error ?: DI::l10n()->t('Internal Server Error'); + $error_description = ''; + $errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description); + + System::jsonError(500, $errorobj->toArray()); + } } From c22846339a360153bd02eeb9d245ae78a4301a93 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 05:30:21 +0000 Subject: [PATCH 09/22] Improved error reporting --- src/Module/Api/Mastodon/Apps.php | 4 ++-- src/Module/BaseApi.php | 18 +++++++++++++----- src/Module/OAuth/Token.php | 10 +++++----- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/Module/Api/Mastodon/Apps.php b/src/Module/Api/Mastodon/Apps.php index 3d06cdbb0..0f0837c78 100644 --- a/src/Module/Api/Mastodon/Apps.php +++ b/src/Module/Api/Mastodon/Apps.php @@ -43,7 +43,7 @@ class Apps extends BaseApi $website = !isset($_REQUEST['website']) ? '' : $_REQUEST['website']; if (empty($name) || empty($redirect)) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Missing parameters')); } $client_id = bin2hex(random_bytes(32)); @@ -60,7 +60,7 @@ class Apps extends BaseApi } if (!DBA::insert('application', $fields)) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->InternalError(); } System::jsonExit(DI::mstdnApplication()->createFromApplicationId(DBA::lastInsertId())); diff --git a/src/Module/BaseApi.php b/src/Module/BaseApi.php index bd42e373d..a0139c637 100644 --- a/src/Module/BaseApi.php +++ b/src/Module/BaseApi.php @@ -193,15 +193,23 @@ class BaseApi extends BaseModule public static function getApplication() { - $redirect_uri = !isset($_REQUEST['redirect_uri']) ? '' : $_REQUEST['redirect_uri']; - $client_id = !isset($_REQUEST['client_id']) ? '' : $_REQUEST['client_id']; + $redirect_uri = !isset($_REQUEST['redirect_uri']) ? '' : $_REQUEST['redirect_uri']; + $client_id = !isset($_REQUEST['client_id']) ? '' : $_REQUEST['client_id']; + $client_secret = !isset($_REQUEST['client_secret']) ? '' : $_REQUEST['client_secret']; - if (empty($redirect_uri) || empty($client_id)) { - Logger::warning('Incomplete request'); + if ((empty($redirect_uri) && empty($client_secret)) || empty($client_id)) { + Logger::warning('Incomplete request', ['request' => $_REQUEST]); return []; } - $condition = ['redirect_uri' => $redirect_uri, 'client_id' => $client_id]; + $condition = ['client_id' => $client_id]; + if (!empty($client_secret)) { + $condition['client_secret'] = $client_secret; + } + if (!empty($redirect_uri)) { + $condition['redirect_uri'] = $redirect_uri; + } + $application = DBA::selectFirst('application', [], $condition); if (!DBA::isResult($application)) { Logger::warning('Application not found', $condition); diff --git a/src/Module/OAuth/Token.php b/src/Module/OAuth/Token.php index 1d0b43cd6..44a862630 100644 --- a/src/Module/OAuth/Token.php +++ b/src/Module/OAuth/Token.php @@ -39,18 +39,18 @@ class Token extends BaseApi $grant_type = !isset($_REQUEST['grant_type']) ? '' : $_REQUEST['grant_type']; if ($grant_type != 'authorization_code') { - Logger::warning('Wrong or missing grant type', ['grant_type' => $grant_type]); - DI::mstdnError()->RecordNotFound(); + Logger::warning('Unsupported or missing grant type', ['request' => $_REQUEST]); + DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Unsupported or missing grant type')); } $application = self::getApplication(); if (empty($application)) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } if ($application['client_secret'] != $client_secret) { Logger::warning('Wrong client secret', $client_secret); - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->Unauthorized(); } $condition = ['application-id' => $application['id'], 'code' => $code]; @@ -58,7 +58,7 @@ class Token extends BaseApi $token = DBA::selectFirst('application-token', ['access_token', 'created_at'], $condition); if (!DBA::isResult($token)) { Logger::warning('Token not found', $condition); - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->Unauthorized(); } // @todo Use entity class From 6ca42512e98296ac3464a85721be4cf9cb6c89fc Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 06:50:27 +0000 Subject: [PATCH 10/22] OAuth connections now have to be ackknowledged --- src/Module/BaseApi.php | 11 +++++++ src/Module/OAuth/Acknowledge.php | 55 ++++++++++++++++++++++++++++++++ src/Module/OAuth/Authorize.php | 15 ++++++--- static/routes.config.php | 11 +++++-- 4 files changed, 85 insertions(+), 7 deletions(-) create mode 100644 src/Module/OAuth/Acknowledge.php diff --git a/src/Module/BaseApi.php b/src/Module/BaseApi.php index a0139c637..d2240fcd6 100644 --- a/src/Module/BaseApi.php +++ b/src/Module/BaseApi.php @@ -218,7 +218,17 @@ class BaseApi extends BaseModule return $application; } + public static function existsTokenForUser(array $application, int $uid) + { + return DBA::exists('application-token', ['application-id' => $application['id'], 'uid' => $uid]); + } + public static function getTokenForUser(array $application, int $uid) + { + return DBA::selectFirst('application-token', [], ['application-id' => $application['id'], 'uid' => $uid]); + } + + public static function createTokenForUser(array $application, int $uid) { $code = bin2hex(random_bytes(32)); $access_token = bin2hex(random_bytes(32)); @@ -230,6 +240,7 @@ class BaseApi extends BaseModule return DBA::selectFirst('application-token', [], ['application-id' => $application['id'], 'uid' => $uid]); } + /** * Get user info array. * diff --git a/src/Module/OAuth/Acknowledge.php b/src/Module/OAuth/Acknowledge.php new file mode 100644 index 000000000..617ab6c53 --- /dev/null +++ b/src/Module/OAuth/Acknowledge.php @@ -0,0 +1,55 @@ +. + * + */ + +namespace Friendica\Module\OAuth; + +use Friendica\Core\Logger; +use Friendica\Core\Renderer; +use Friendica\DI; +use Friendica\Module\BaseApi; + +/** + * Dummy class for all currently unimplemented endpoints + */ +class Acknowledge extends BaseApi +{ + public static function post(array $parameters = []) + { + DI::session()->set('oauth_acknowledge', true); + DI::app()->redirect(DI::session()->get('return_path')); + } + + public static function content(array $parameters = []) + { + DI::session()->set('return_path', $_REQUEST['return_path'] ?? ''); + + $tpl = Renderer::getMarkupTemplate('oauth_authorize.tpl'); + $o = Renderer::replaceMacros($tpl, [ + '$title' => DI::l10n()->t('Authorize application connection'), + '$app' => ['name' => $_REQUEST['application'] ?? ''], + '$authorize' => DI::l10n()->t('Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?'), + '$yes' => DI::l10n()->t('Yes'), + '$no' => DI::l10n()->t('No'), + ]); + + return $o; + } +} diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index 8afc7d48a..4c2d9c027 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -47,17 +47,24 @@ class Authorize extends BaseApi DI::mstdnError()->RecordNotFound(); } + $request = $_REQUEST; + unset($request['pagename']); + $redirect = urlencode('oauth/authorize?' . http_build_query($request)); + $uid = local_user(); if (empty($uid)) { Logger::info('Redirect to login'); - $request = $_REQUEST; - unset($request['pagename']); - DI::app()->redirect('login?return_path=' . urlencode('/oauth/authorize?' . http_build_query($request))); + DI::app()->redirect('login?return_path=' . $redirect); } else { Logger::info('Already logged in user', ['uid' => $uid]); } - $token = self::getTokenForUser($application, $uid); + if (!self::existsTokenForUser($application, $uid) && !DI::session()->get('oauth_acknowledge')) { + Logger::info('Redirect to acknowledge'); + DI::app()->redirect('oauth/acknowledge?return_path=' . $redirect); + } + + $token = self::createTokenForUser($application, $uid); if (!$token) { DI::mstdnError()->RecordNotFound(); } diff --git a/static/routes.config.php b/static/routes.config.php index f666feeff..9d8e1fda4 100644 --- a/static/routes.config.php +++ b/static/routes.config.php @@ -331,9 +331,14 @@ return [ '/mark/all' => [Module\Notifications\Notification::class, [R::GET]], '/{id:\d+}' => [Module\Notifications\Notification::class, [R::GET, R::POST]], ], - '/oauth/authorize' => [Module\OAuth\Authorize::class, [R::GET]], - '/oauth/revoke' => [Module\OAuth\Revoke::class, [R::POST]], - '/oauth/token' => [Module\OAuth\Token::class, [R::POST]], + + '/oauth' => [ + '/acknowledge' => [Module\OAuth\Acknowledge::class, [R::GET, R::POST]], + '/authorize' => [Module\OAuth\Authorize::class, [R::GET]], + '/revoke' => [Module\OAuth\Revoke::class, [R::POST]], + '/token' => [Module\OAuth\Token::class, [R::POST]], + ], + '/objects/{guid}[/{activity}]' => [Module\Objects::class, [R::GET]], '/oembed' => [ From a23d108fa715d10ed0179ff54f0d95f5224720f4 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 06:51:59 +0000 Subject: [PATCH 11/22] Session variable needs to be removed afterwards --- src/Module/OAuth/Authorize.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index 4c2d9c027..ffa725532 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -64,6 +64,8 @@ class Authorize extends BaseApi DI::app()->redirect('oauth/acknowledge?return_path=' . $redirect); } + DI::session()->remove('oauth_acknowledge'); + $token = self::createTokenForUser($application, $uid); if (!$token) { DI::mstdnError()->RecordNotFound(); From c3f28252ff8b313397d1b47db4ef7973ce8c348a Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 10:50:01 +0000 Subject: [PATCH 12/22] Indention --- src/Module/OAuth/Acknowledge.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Module/OAuth/Acknowledge.php b/src/Module/OAuth/Acknowledge.php index 617ab6c53..1797b5fa0 100644 --- a/src/Module/OAuth/Acknowledge.php +++ b/src/Module/OAuth/Acknowledge.php @@ -43,11 +43,11 @@ class Acknowledge extends BaseApi $tpl = Renderer::getMarkupTemplate('oauth_authorize.tpl'); $o = Renderer::replaceMacros($tpl, [ - '$title' => DI::l10n()->t('Authorize application connection'), - '$app' => ['name' => $_REQUEST['application'] ?? ''], + '$title' => DI::l10n()->t('Authorize application connection'), + '$app' => ['name' => $_REQUEST['application'] ?? ''], '$authorize' => DI::l10n()->t('Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?'), - '$yes' => DI::l10n()->t('Yes'), - '$no' => DI::l10n()->t('No'), + '$yes' => DI::l10n()->t('Yes'), + '$no' => DI::l10n()->t('No'), ]); return $o; From daa832fcf9f704ba7385f062509a400c83383f20 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 11:54:43 +0000 Subject: [PATCH 13/22] Formatting --- src/Module/OAuth/Acknowledge.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Module/OAuth/Acknowledge.php b/src/Module/OAuth/Acknowledge.php index 1797b5fa0..580f78c3c 100644 --- a/src/Module/OAuth/Acknowledge.php +++ b/src/Module/OAuth/Acknowledge.php @@ -41,8 +41,7 @@ class Acknowledge extends BaseApi { DI::session()->set('return_path', $_REQUEST['return_path'] ?? ''); - $tpl = Renderer::getMarkupTemplate('oauth_authorize.tpl'); - $o = Renderer::replaceMacros($tpl, [ + $o = Renderer::replaceMacros(Renderer::getMarkupTemplate('oauth_authorize.tpl'), [ '$title' => DI::l10n()->t('Authorize application connection'), '$app' => ['name' => $_REQUEST['application'] ?? ''], '$authorize' => DI::l10n()->t('Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?'), From 87f7e26638335719aab58bea6a774e29fa73dc3c Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 12:00:24 +0000 Subject: [PATCH 14/22] Added documentation --- src/Module/OAuth/Acknowledge.php | 3 +-- src/Module/OAuth/Authorize.php | 2 +- src/Module/OAuth/Revoke.php | 2 +- src/Module/OAuth/Token.php | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Module/OAuth/Acknowledge.php b/src/Module/OAuth/Acknowledge.php index 580f78c3c..6f7ac945b 100644 --- a/src/Module/OAuth/Acknowledge.php +++ b/src/Module/OAuth/Acknowledge.php @@ -21,13 +21,12 @@ namespace Friendica\Module\OAuth; -use Friendica\Core\Logger; use Friendica\Core\Renderer; use Friendica\DI; use Friendica\Module\BaseApi; /** - * Dummy class for all currently unimplemented endpoints + * Acknowledgement of OAuth requests */ class Acknowledge extends BaseApi { diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index ffa725532..203ed7474 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -26,7 +26,7 @@ use Friendica\DI; use Friendica\Module\BaseApi; /** - * Dummy class for all currently unimplemented endpoints + * @see https://docs.joinmastodon.org/spec/oauth/ */ class Authorize extends BaseApi { diff --git a/src/Module/OAuth/Revoke.php b/src/Module/OAuth/Revoke.php index b38133570..c64193243 100644 --- a/src/Module/OAuth/Revoke.php +++ b/src/Module/OAuth/Revoke.php @@ -24,7 +24,7 @@ namespace Friendica\Module\OAuth; use Friendica\Module\BaseApi; /** - * Dummy class for all currently unimplemented endpoints + * @see https://docs.joinmastodon.org/spec/oauth/ */ class Revoke extends BaseApi { diff --git a/src/Module/OAuth/Token.php b/src/Module/OAuth/Token.php index 44a862630..164623482 100644 --- a/src/Module/OAuth/Token.php +++ b/src/Module/OAuth/Token.php @@ -28,7 +28,7 @@ use Friendica\DI; use Friendica\Module\BaseApi; /** - * Dummy class for all currently unimplemented endpoints + * @see https://docs.joinmastodon.org/spec/oauth/ */ class Token extends BaseApi { From 19a81d25d5ca00ab503fd598918201d2164ac42f Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 12:08:30 +0000 Subject: [PATCH 15/22] Added documentation headers --- src/Module/BaseApi.php | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/Module/BaseApi.php b/src/Module/BaseApi.php index d2240fcd6..046280473 100644 --- a/src/Module/BaseApi.php +++ b/src/Module/BaseApi.php @@ -110,12 +110,18 @@ class BaseApi extends BaseModule } } + /** + * 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' => $_REQUEST ?? []]); $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.');; + $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()); } @@ -143,6 +149,7 @@ class BaseApi extends BaseModule } if (empty(self::$current_user_id)) { + // The execution stops here if no one is logged in api_login(DI::app()); } @@ -163,6 +170,7 @@ class BaseApi extends BaseModule } if (empty(self::$current_user_id)) { + // Fetch the user id if logged in - but don't fail if not api_login(DI::app(), false); self::$current_user_id = api_user(); @@ -171,6 +179,11 @@ class BaseApi extends BaseModule return (int)self::$current_user_id; } + /** + * Get the user id via the Bearer token + * + * @return int User-ID + */ private static function getUserByBearer() { $authorization = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; @@ -191,6 +204,11 @@ class BaseApi extends BaseModule return $token['uid']; } + /** + * Get the application record via the proved request header fields + * + * @return array application record + */ public static function getApplication() { $redirect_uri = !isset($_REQUEST['redirect_uri']) ? '' : $_REQUEST['redirect_uri']; @@ -218,16 +236,37 @@ class BaseApi extends BaseModule return $application; } + /** + * Check if an token for the application and user exists + * + * @param array $application + * @param integer $uid + * @return boolean + */ public static function existsTokenForUser(array $application, int $uid) { return DBA::exists('application-token', ['application-id' => $application['id'], 'uid' => $uid]); } + /** + * Fetch the token for the given application and user + * + * @param array $application + * @param integer $uid + * @return array application record + */ public static function getTokenForUser(array $application, int $uid) { return DBA::selectFirst('application-token', [], ['application-id' => $application['id'], 'uid' => $uid]); } + /** + * Create and fetch an token for the application and user + * + * @param array $application + * @param integer $uid + * @return array application record + */ public static function createTokenForUser(array $application, int $uid) { $code = bin2hex(random_bytes(32)); From 8dccb66decf9d9c7d8a9004c880fe20f6b6441c6 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 12:19:15 +0000 Subject: [PATCH 16/22] Display the application name --- src/Module/OAuth/Authorize.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index 203ed7474..a93fc0038 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -49,19 +49,19 @@ class Authorize extends BaseApi $request = $_REQUEST; unset($request['pagename']); - $redirect = urlencode('oauth/authorize?' . http_build_query($request)); + $redirect = 'oauth/authorize?' . http_build_query($request); $uid = local_user(); if (empty($uid)) { Logger::info('Redirect to login'); - DI::app()->redirect('login?return_path=' . $redirect); + DI::app()->redirect('login?return_path=' . urlencode($redirect)); } else { Logger::info('Already logged in user', ['uid' => $uid]); } if (!self::existsTokenForUser($application, $uid) && !DI::session()->get('oauth_acknowledge')) { Logger::info('Redirect to acknowledge'); - DI::app()->redirect('oauth/acknowledge?return_path=' . $redirect); + DI::app()->redirect('oauth/acknowledge?' . http_build_query(['return_path' => $redirect, 'application' => $application['name']])); } DI::session()->remove('oauth_acknowledge'); From b2fe039dabd75a29b8d2400a5f2def3c4a31659b Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 12:28:13 +0000 Subject: [PATCH 17/22] oauth template redesigned --- view/templates/oauth_authorize.tpl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/view/templates/oauth_authorize.tpl b/view/templates/oauth_authorize.tpl index 10d9d5069..244ef492d 100644 --- a/view/templates/oauth_authorize.tpl +++ b/view/templates/oauth_authorize.tpl @@ -1,11 +1,11 @@ -

{{$title}}

+

{{$title}}

- -

{{$app.name}}

+{{if {{$app.icon}}}}{{/if}} +

{{$app.name}}

-

{{$authorize}}

+

{{$authorize}}

-
+
From 4a6d33e1824b32768c4a33653fefe75bf337e13d Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 12:34:55 +0000 Subject: [PATCH 18/22] HTTP_AUTHORIZATION should be enough --- src/Module/BaseApi.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Module/BaseApi.php b/src/Module/BaseApi.php index 046280473..27c4fee10 100644 --- a/src/Module/BaseApi.php +++ b/src/Module/BaseApi.php @@ -187,7 +187,6 @@ class BaseApi extends BaseModule private static function getUserByBearer() { $authorization = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; - $authorization = $_SERVER['AUTHORIZATION'] ?? $authorization; if (substr($authorization, 0, 7) != 'Bearer ') { return 0; From 8a5560ec8f1474b8f250abc7db61a0048f1a88e2 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 12:40:45 +0000 Subject: [PATCH 19/22] Simplified null check --- src/Module/Api/Mastodon/Apps.php | 8 ++++---- src/Module/Api/Mastodon/Directory.php | 2 +- src/Module/Api/Mastodon/Notifications.php | 2 +- src/Module/BaseApi.php | 6 +++--- src/Module/OAuth/Authorize.php | 2 +- src/Module/OAuth/Token.php | 6 +++--- src/Module/Security/Login.php | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Module/Api/Mastodon/Apps.php b/src/Module/Api/Mastodon/Apps.php index 0f0837c78..7b13b1701 100644 --- a/src/Module/Api/Mastodon/Apps.php +++ b/src/Module/Api/Mastodon/Apps.php @@ -37,10 +37,10 @@ class Apps extends BaseApi */ public static function post(array $parameters = []) { - $name = !isset($_REQUEST['client_name']) ? '' : $_REQUEST['client_name']; - $redirect = !isset($_REQUEST['redirect_uris']) ? '' : $_REQUEST['redirect_uris']; - $scopes = !isset($_REQUEST['scopes']) ? '' : $_REQUEST['scopes']; - $website = !isset($_REQUEST['website']) ? '' : $_REQUEST['website']; + $name = $_REQUEST['client_name'] ?? ''; + $redirect = $_REQUEST['redirect_uris'] ?? ''; + $scopes = $_REQUEST['scopes'] ?? ''; + $website = $_REQUEST['website'] ?? ''; if (empty($name) || empty($redirect)) { DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Missing parameters')); diff --git a/src/Module/Api/Mastodon/Directory.php b/src/Module/Api/Mastodon/Directory.php index 70046642c..f2849f7f8 100644 --- a/src/Module/Api/Mastodon/Directory.php +++ b/src/Module/Api/Mastodon/Directory.php @@ -44,7 +44,7 @@ class Directory extends BaseApi { $offset = (int)!isset($_REQUEST['offset']) ? 0 : $_REQUEST['offset']; $limit = (int)!isset($_REQUEST['limit']) ? 40 : $_REQUEST['limit']; - $order = !isset($_REQUEST['order']) ? 'active' : $_REQUEST['order']; + $order = $_REQUEST['order'] ?? 'active'; $local = (bool)!isset($_REQUEST['local']) ? false : ($_REQUEST['local'] == 'true'); Logger::info('directory', ['offset' => $offset, 'limit' => $limit, 'order' => $order, 'local' => $local]); diff --git a/src/Module/Api/Mastodon/Notifications.php b/src/Module/Api/Mastodon/Notifications.php index a10ebf5d5..8252de7c2 100644 --- a/src/Module/Api/Mastodon/Notifications.php +++ b/src/Module/Api/Mastodon/Notifications.php @@ -63,7 +63,7 @@ class Notifications extends BaseApi $limit = (int)!isset($_REQUEST['limit']) ? 20 : $_REQUEST['limit']; // Array of types to exclude (follow, favourite, reblog, mention, poll, follow_request) - $exclude_types = !isset($_REQUEST['exclude_types']) ? [] : $_REQUEST['exclude_types']; + $exclude_types = $_REQUEST['exclude_types'] ?? []; // Return only notifications received from this account $account_id = (int)!isset($_REQUEST['account_id']) ? 0 : $_REQUEST['account_id']; diff --git a/src/Module/BaseApi.php b/src/Module/BaseApi.php index 27c4fee10..b4f228a6e 100644 --- a/src/Module/BaseApi.php +++ b/src/Module/BaseApi.php @@ -210,9 +210,9 @@ class BaseApi extends BaseModule */ public static function getApplication() { - $redirect_uri = !isset($_REQUEST['redirect_uri']) ? '' : $_REQUEST['redirect_uri']; - $client_id = !isset($_REQUEST['client_id']) ? '' : $_REQUEST['client_id']; - $client_secret = !isset($_REQUEST['client_secret']) ? '' : $_REQUEST['client_secret']; + $redirect_uri = $_REQUEST['redirect_uri'] ?? ''; + $client_id = $_REQUEST['client_id'] ?? ''; + $client_secret = $_REQUEST['client_secret'] ?? ''; if ((empty($redirect_uri) && empty($client_secret)) || empty($client_id)) { Logger::warning('Incomplete request', ['request' => $_REQUEST]); diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index a93fc0038..c9bf7b687 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -36,7 +36,7 @@ class Authorize extends BaseApi */ public static function rawContent(array $parameters = []) { - $response_type = !isset($_REQUEST['response_type']) ? '' : $_REQUEST['response_type']; + $response_type = $_REQUEST['response_type'] ?? ''; if ($response_type != 'code') { Logger::warning('Wrong or missing response type', ['response_type' => $response_type]); DI::mstdnError()->RecordNotFound(); diff --git a/src/Module/OAuth/Token.php b/src/Module/OAuth/Token.php index 164623482..17f2e2b82 100644 --- a/src/Module/OAuth/Token.php +++ b/src/Module/OAuth/Token.php @@ -34,9 +34,9 @@ class Token extends BaseApi { public static function post(array $parameters = []) { - $client_secret = !isset($_REQUEST['client_secret']) ? '' : $_REQUEST['client_secret']; - $code = !isset($_REQUEST['code']) ? '' : $_REQUEST['code']; - $grant_type = !isset($_REQUEST['grant_type']) ? '' : $_REQUEST['grant_type']; + $client_secret = $_REQUEST['client_secret'] ?? ''; + $code = $_REQUEST['code'] ?? ''; + $grant_type = $_REQUEST['grant_type'] ?? ''; if ($grant_type != 'authorization_code') { Logger::warning('Unsupported or missing grant type', ['request' => $_REQUEST]); diff --git a/src/Module/Security/Login.php b/src/Module/Security/Login.php index 80a966220..1d45b6c9d 100644 --- a/src/Module/Security/Login.php +++ b/src/Module/Security/Login.php @@ -36,7 +36,7 @@ class Login extends BaseModule { public static function content(array $parameters = []) { - $return_path = !isset($_REQUEST['return_path']) ? '' : $_REQUEST['return_path']; + $return_path = $_REQUEST['return_path'] ?? '' ; if (local_user()) { DI::baseUrl()->redirect($return_path); From 9125d296a15ad147f3807dd3eb135ec103779308 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 14:00:15 +0000 Subject: [PATCH 20/22] Improved error messages --- src/Module/Api/Mastodon/Accounts.php | 2 +- src/Module/Api/Mastodon/Accounts/Followers.php | 2 +- src/Module/Api/Mastodon/Accounts/Following.php | 2 +- src/Module/Api/Mastodon/Accounts/Lists.php | 2 +- src/Module/Api/Mastodon/Accounts/Statuses.php | 2 +- src/Module/Api/Mastodon/Accounts/VerifyCredentials.php | 4 ++-- src/Module/Api/Mastodon/Blocks.php | 2 +- src/Module/Api/Mastodon/Lists/Accounts.php | 2 +- src/Module/Api/Mastodon/Media.php | 2 +- src/Module/Api/Mastodon/Mutes.php | 2 +- src/Module/Api/Mastodon/Statuses.php | 2 +- src/Module/Api/Mastodon/Statuses/Context.php | 2 +- src/Module/Api/Mastodon/Statuses/FavouritedBy.php | 2 +- src/Module/Api/Mastodon/Statuses/RebloggedBy.php | 2 +- src/Module/Api/Mastodon/Timelines/ListTimeline.php | 2 +- src/Module/Api/Mastodon/Timelines/Tag.php | 2 +- src/Module/OAuth/Authorize.php | 6 +++--- 17 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/Module/Api/Mastodon/Accounts.php b/src/Module/Api/Mastodon/Accounts.php index 0d48744a4..a5c9b8104 100644 --- a/src/Module/Api/Mastodon/Accounts.php +++ b/src/Module/Api/Mastodon/Accounts.php @@ -38,7 +38,7 @@ class Accounts extends BaseApi public static function rawContent(array $parameters = []) { if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $id = $parameters['id']; diff --git a/src/Module/Api/Mastodon/Accounts/Followers.php b/src/Module/Api/Mastodon/Accounts/Followers.php index ab2ca6839..7e082edbd 100644 --- a/src/Module/Api/Mastodon/Accounts/Followers.php +++ b/src/Module/Api/Mastodon/Accounts/Followers.php @@ -41,7 +41,7 @@ class Followers extends BaseApi $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $id = $parameters['id']; diff --git a/src/Module/Api/Mastodon/Accounts/Following.php b/src/Module/Api/Mastodon/Accounts/Following.php index 414213dc4..87e9117ea 100644 --- a/src/Module/Api/Mastodon/Accounts/Following.php +++ b/src/Module/Api/Mastodon/Accounts/Following.php @@ -41,7 +41,7 @@ class Following extends BaseApi $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $id = $parameters['id']; diff --git a/src/Module/Api/Mastodon/Accounts/Lists.php b/src/Module/Api/Mastodon/Accounts/Lists.php index b15124a45..6ba7953ab 100644 --- a/src/Module/Api/Mastodon/Accounts/Lists.php +++ b/src/Module/Api/Mastodon/Accounts/Lists.php @@ -42,7 +42,7 @@ class Lists extends BaseApi $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $id = $parameters['id']; diff --git a/src/Module/Api/Mastodon/Accounts/Statuses.php b/src/Module/Api/Mastodon/Accounts/Statuses.php index 14cd19e42..b3aec744e 100644 --- a/src/Module/Api/Mastodon/Accounts/Statuses.php +++ b/src/Module/Api/Mastodon/Accounts/Statuses.php @@ -43,7 +43,7 @@ class Statuses extends BaseApi public static function rawContent(array $parameters = []) { if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $id = $parameters['id']; diff --git a/src/Module/Api/Mastodon/Accounts/VerifyCredentials.php b/src/Module/Api/Mastodon/Accounts/VerifyCredentials.php index 94fa32684..facae7259 100644 --- a/src/Module/Api/Mastodon/Accounts/VerifyCredentials.php +++ b/src/Module/Api/Mastodon/Accounts/VerifyCredentials.php @@ -43,12 +43,12 @@ class VerifyCredentials extends BaseApi $self = User::getOwnerDataById($uid); if (empty($self)) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->InternalError(); } $cdata = Contact::getPublicAndUserContacID($self['id'], $uid); if (empty($cdata)) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->InternalError(); } // @todo Support the source property, diff --git a/src/Module/Api/Mastodon/Blocks.php b/src/Module/Api/Mastodon/Blocks.php index af8e77f88..e93743ac2 100644 --- a/src/Module/Api/Mastodon/Blocks.php +++ b/src/Module/Api/Mastodon/Blocks.php @@ -41,7 +41,7 @@ class Blocks extends BaseApi $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $id = $parameters['id']; diff --git a/src/Module/Api/Mastodon/Lists/Accounts.php b/src/Module/Api/Mastodon/Lists/Accounts.php index 513ca21d7..cb2bd208f 100644 --- a/src/Module/Api/Mastodon/Lists/Accounts.php +++ b/src/Module/Api/Mastodon/Lists/Accounts.php @@ -53,7 +53,7 @@ class Accounts extends BaseApi $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $id = $parameters['id']; diff --git a/src/Module/Api/Mastodon/Media.php b/src/Module/Api/Mastodon/Media.php index bc55610b2..297d7d7a3 100644 --- a/src/Module/Api/Mastodon/Media.php +++ b/src/Module/Api/Mastodon/Media.php @@ -46,7 +46,7 @@ class Media extends BaseApi $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $id = $parameters['id']; diff --git a/src/Module/Api/Mastodon/Mutes.php b/src/Module/Api/Mastodon/Mutes.php index cb981b33e..d49bdad68 100644 --- a/src/Module/Api/Mastodon/Mutes.php +++ b/src/Module/Api/Mastodon/Mutes.php @@ -41,7 +41,7 @@ class Mutes extends BaseApi $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $id = $parameters['id']; diff --git a/src/Module/Api/Mastodon/Statuses.php b/src/Module/Api/Mastodon/Statuses.php index 042d038a2..900452385 100644 --- a/src/Module/Api/Mastodon/Statuses.php +++ b/src/Module/Api/Mastodon/Statuses.php @@ -42,7 +42,7 @@ class Statuses extends BaseApi public static function rawContent(array $parameters = []) { if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], self::getCurrentUserID())); diff --git a/src/Module/Api/Mastodon/Statuses/Context.php b/src/Module/Api/Mastodon/Statuses/Context.php index 5615e41cc..345a473db 100644 --- a/src/Module/Api/Mastodon/Statuses/Context.php +++ b/src/Module/Api/Mastodon/Statuses/Context.php @@ -41,7 +41,7 @@ class Context extends BaseApi $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $id = $parameters['id']; diff --git a/src/Module/Api/Mastodon/Statuses/FavouritedBy.php b/src/Module/Api/Mastodon/Statuses/FavouritedBy.php index 7c784c802..cecf0336a 100644 --- a/src/Module/Api/Mastodon/Statuses/FavouritedBy.php +++ b/src/Module/Api/Mastodon/Statuses/FavouritedBy.php @@ -41,7 +41,7 @@ class FavouritedBy extends BaseApi $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $id = $parameters['id']; diff --git a/src/Module/Api/Mastodon/Statuses/RebloggedBy.php b/src/Module/Api/Mastodon/Statuses/RebloggedBy.php index 3701afb0d..9faf034ae 100644 --- a/src/Module/Api/Mastodon/Statuses/RebloggedBy.php +++ b/src/Module/Api/Mastodon/Statuses/RebloggedBy.php @@ -41,7 +41,7 @@ class RebloggedBy extends BaseApi $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $id = $parameters['id']; diff --git a/src/Module/Api/Mastodon/Timelines/ListTimeline.php b/src/Module/Api/Mastodon/Timelines/ListTimeline.php index df5c21122..7da16d137 100644 --- a/src/Module/Api/Mastodon/Timelines/ListTimeline.php +++ b/src/Module/Api/Mastodon/Timelines/ListTimeline.php @@ -43,7 +43,7 @@ class ListTimeline extends BaseApi $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } // Return results older than id diff --git a/src/Module/Api/Mastodon/Timelines/Tag.php b/src/Module/Api/Mastodon/Timelines/Tag.php index f61e3c3f7..7218f40cb 100644 --- a/src/Module/Api/Mastodon/Timelines/Tag.php +++ b/src/Module/Api/Mastodon/Timelines/Tag.php @@ -44,7 +44,7 @@ class Tag extends BaseApi $uid = self::getCurrentUserID(); if (empty($parameters['hashtag'])) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } // If true, return only local statuses. Defaults to false. diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index c9bf7b687..7d9f67ad3 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -39,12 +39,12 @@ class Authorize extends BaseApi $response_type = $_REQUEST['response_type'] ?? ''; if ($response_type != 'code') { Logger::warning('Wrong or missing response type', ['response_type' => $response_type]); - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $application = self::getApplication(); if (empty($application)) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } $request = $_REQUEST; @@ -68,7 +68,7 @@ class Authorize extends BaseApi $token = self::createTokenForUser($application, $uid); if (!$token) { - DI::mstdnError()->RecordNotFound(); + DI::mstdnError()->UnprocessableEntity(); } DI::app()->redirect($application['redirect_uri'] . '?code=' . $token['code']); From 4fb52385a8aabc41d771214deb85e7f6a00711e0 Mon Sep 17 00:00:00 2001 From: Michael Vogel Date: Wed, 12 May 2021 17:32:55 +0200 Subject: [PATCH 21/22] Apply suggestions from code review Co-authored-by: Hypolite Petovan --- view/templates/oauth_authorize.tpl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/view/templates/oauth_authorize.tpl b/view/templates/oauth_authorize.tpl index 244ef492d..5f33c68d3 100644 --- a/view/templates/oauth_authorize.tpl +++ b/view/templates/oauth_authorize.tpl @@ -1,8 +1,8 @@

{{$title}}

-
-{{if {{$app.icon}}}}{{/if}} +
+{{if $app.icon}}{{/if}}

{{$app.name}}

{{$authorize}}

From 494e852c1a1196972404737c43141d2eb01c7f48 Mon Sep 17 00:00:00 2001 From: Michael Date: Wed, 12 May 2021 15:41:05 +0000 Subject: [PATCH 22/22] Removed old comment --- src/Module/Api/Mastodon/Accounts/Statuses.php | 2 +- src/Module/Api/Mastodon/Timelines/PublicTimeline.php | 2 +- src/Module/Api/Mastodon/Timelines/Tag.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Module/Api/Mastodon/Accounts/Statuses.php b/src/Module/Api/Mastodon/Accounts/Statuses.php index b3aec744e..e234b7ee1 100644 --- a/src/Module/Api/Mastodon/Accounts/Statuses.php +++ b/src/Module/Api/Mastodon/Accounts/Statuses.php @@ -52,7 +52,7 @@ class Statuses extends BaseApi } // Show only statuses with media attached? Defaults to false. - $only_media = (bool)!isset($_REQUEST['only_media']) ? false : ($_REQUEST['only_media'] == 'true'); // Currently not supported + $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 diff --git a/src/Module/Api/Mastodon/Timelines/PublicTimeline.php b/src/Module/Api/Mastodon/Timelines/PublicTimeline.php index a0a975d20..487b45e34 100644 --- a/src/Module/Api/Mastodon/Timelines/PublicTimeline.php +++ b/src/Module/Api/Mastodon/Timelines/PublicTimeline.php @@ -46,7 +46,7 @@ class PublicTimeline extends BaseApi // Show only remote statuses? Defaults to false. $remote = (bool)!isset($_REQUEST['remote']) ? false : ($_REQUEST['remote'] == 'true'); // Show only statuses with media attached? Defaults to false. - $only_media = (bool)!isset($_REQUEST['only_media']) ? false : ($_REQUEST['only_media'] == 'true'); // Currently not supported + $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 diff --git a/src/Module/Api/Mastodon/Timelines/Tag.php b/src/Module/Api/Mastodon/Timelines/Tag.php index 7218f40cb..924b76307 100644 --- a/src/Module/Api/Mastodon/Timelines/Tag.php +++ b/src/Module/Api/Mastodon/Timelines/Tag.php @@ -50,7 +50,7 @@ class Tag extends BaseApi // 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'); // Currently not supported + $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.