diff --git a/include/api.php b/include/api.php index 935bd11d6..421086002 100644 --- a/include/api.php +++ b/include/api.php @@ -44,7 +44,6 @@ use Friendica\Model\Photo; use Friendica\Model\Post; use Friendica\Model\User; use Friendica\Model\Verb; -use Friendica\Module\BaseApi; use Friendica\Network\HTTPException; use Friendica\Network\HTTPException\BadRequestException; use Friendica\Network\HTTPException\ExpectationFailedException; @@ -58,6 +57,7 @@ use Friendica\Object\Image; use Friendica\Protocol\Activity; use Friendica\Protocol\Diaspora; use Friendica\Security\FKOAuth1; +use Friendica\Security\OAuth; use Friendica\Security\OAuth1\OAuthRequest; use Friendica\Security\OAuth1\OAuthUtil; use Friendica\Util\DateTimeFormat; @@ -89,7 +89,7 @@ $called_api = []; */ function api_user() { - $user = BaseApi::getCurrentUserID(true); + $user = OAuth::getCurrentUserID(); if (!empty($user)) { return $user; } diff --git a/src/Module/Api/Friendica/Events/Index.php b/src/Module/Api/Friendica/Events/Index.php index 53408541a..d53273ef6 100644 --- a/src/Module/Api/Friendica/Events/Index.php +++ b/src/Module/Api/Friendica/Events/Index.php @@ -35,16 +35,15 @@ class Index extends BaseApi { public static function rawContent(array $parameters = []) { - if (self::login(self::SCOPE_READ) === false) { - throw new HTTPException\ForbiddenException(); - } + self::checkAllowedScope(self::SCOPE_READ); + $uid = self::getCurrentUserID(); $request = self::getRequest([ 'since_id' => 0, 'count' => 0, ]); - $condition = ["`id` > ? AND `uid` = ?", $request['since_id'], self::$current_user_id]; + $condition = ["`id` > ? AND `uid` = ?", $request['since_id'], $uid]; $params = ['limit' => $request['count']]; $events = DBA::selectToArray('event', [], $condition, $params); diff --git a/src/Module/Api/Friendica/Profile/Show.php b/src/Module/Api/Friendica/Profile/Show.php index e550f839c..9058ba521 100644 --- a/src/Module/Api/Friendica/Profile/Show.php +++ b/src/Module/Api/Friendica/Profile/Show.php @@ -37,16 +37,15 @@ class Show extends BaseApi { public static function rawContent(array $parameters = []) { - if (self::login(self::SCOPE_READ) === false) { - throw new HTTPException\ForbiddenException(); - } + self::checkAllowedScope(self::SCOPE_READ); + $uid = self::getCurrentUserID(); // retrieve general information about profiles for user $directory = DI::config()->get('system', 'directory'); - $profile = Profile::getByUID(self::$current_user_id); + $profile = Profile::getByUID($uid); - $profileFields = DI::profileField()->select(['uid' => self::$current_user_id, 'psid' => PermissionSet::PUBLIC]); + $profileFields = DI::profileField()->select(['uid' => $uid, 'psid' => PermissionSet::PUBLIC]); $profile = self::formatProfile($profile, $profileFields); @@ -58,7 +57,7 @@ class Show extends BaseApi } // return settings, authenticated user and profiles data - $self = Contact::selectFirst(['nurl'], ['uid' => self::$current_user_id, 'self' => true]); + $self = Contact::selectFirst(['nurl'], ['uid' => $uid, 'self' => true]); $result = [ 'multi_profiles' => false, diff --git a/src/Module/Api/Mastodon/Accounts.php b/src/Module/Api/Mastodon/Accounts.php index f650af058..781547854 100644 --- a/src/Module/Api/Mastodon/Accounts.php +++ b/src/Module/Api/Mastodon/Accounts.php @@ -38,6 +38,8 @@ class Accounts extends BaseApi */ public static function rawContent(array $parameters = []) { + $uid = self::getCurrentUserID(); + if (empty($parameters['id']) && empty($parameters['name'])) { DI::mstdnError()->UnprocessableEntity(); } @@ -56,7 +58,7 @@ class Accounts extends BaseApi } } - $account = DI::mstdnAccount()->createFromContactId($id, self::getCurrentUserID()); + $account = DI::mstdnAccount()->createFromContactId($id, $uid); System::jsonExit($account); } } diff --git a/src/Module/Api/Mastodon/Accounts/Block.php b/src/Module/Api/Mastodon/Accounts/Block.php index fa12daaf4..211148049 100644 --- a/src/Module/Api/Mastodon/Accounts/Block.php +++ b/src/Module/Api/Mastodon/Accounts/Block.php @@ -33,7 +33,7 @@ class Block extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_FOLLOW); + self::checkAllowedScope(self::SCOPE_FOLLOW); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Accounts/Follow.php b/src/Module/Api/Mastodon/Accounts/Follow.php index bdd21c737..ab7038e97 100644 --- a/src/Module/Api/Mastodon/Accounts/Follow.php +++ b/src/Module/Api/Mastodon/Accounts/Follow.php @@ -33,14 +33,14 @@ class Follow extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_FOLLOW); + self::checkAllowedScope(self::SCOPE_FOLLOW); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { DI::mstdnError()->UnprocessableEntity(); } - $cid = Contact::follow($parameters['id'], self::getCurrentUserID()); + $cid = Contact::follow($parameters['id'], $uid); System::jsonExit(DI::mstdnRelationship()->createFromContactId($cid, $uid)->toArray()); } diff --git a/src/Module/Api/Mastodon/Accounts/Followers.php b/src/Module/Api/Mastodon/Accounts/Followers.php index c311b693e..666cafc42 100644 --- a/src/Module/Api/Mastodon/Accounts/Followers.php +++ b/src/Module/Api/Mastodon/Accounts/Followers.php @@ -37,7 +37,7 @@ class Followers extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Accounts/Following.php b/src/Module/Api/Mastodon/Accounts/Following.php index 53908b36b..c967715df 100644 --- a/src/Module/Api/Mastodon/Accounts/Following.php +++ b/src/Module/Api/Mastodon/Accounts/Following.php @@ -37,7 +37,7 @@ class Following extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Accounts/IdentityProofs.php b/src/Module/Api/Mastodon/Accounts/IdentityProofs.php index f92de6cad..6abb416d1 100644 --- a/src/Module/Api/Mastodon/Accounts/IdentityProofs.php +++ b/src/Module/Api/Mastodon/Accounts/IdentityProofs.php @@ -35,7 +35,7 @@ class IdentityProofs extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); System::jsonExit([]); } diff --git a/src/Module/Api/Mastodon/Accounts/Lists.php b/src/Module/Api/Mastodon/Accounts/Lists.php index 6a3e87b42..b962594ff 100644 --- a/src/Module/Api/Mastodon/Accounts/Lists.php +++ b/src/Module/Api/Mastodon/Accounts/Lists.php @@ -38,7 +38,7 @@ class Lists extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Accounts/Mute.php b/src/Module/Api/Mastodon/Accounts/Mute.php index 19413bacf..1d878269d 100644 --- a/src/Module/Api/Mastodon/Accounts/Mute.php +++ b/src/Module/Api/Mastodon/Accounts/Mute.php @@ -33,7 +33,7 @@ class Mute extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_FOLLOW); + self::checkAllowedScope(self::SCOPE_FOLLOW); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Accounts/Note.php b/src/Module/Api/Mastodon/Accounts/Note.php index 477bcb824..f78d58bac 100644 --- a/src/Module/Api/Mastodon/Accounts/Note.php +++ b/src/Module/Api/Mastodon/Accounts/Note.php @@ -34,7 +34,7 @@ class Note extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Accounts/Relationships.php b/src/Module/Api/Mastodon/Accounts/Relationships.php index 9e966d215..12d5f2e66 100644 --- a/src/Module/Api/Mastodon/Accounts/Relationships.php +++ b/src/Module/Api/Mastodon/Accounts/Relationships.php @@ -37,7 +37,7 @@ class Relationships extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); $request = self::getRequest([ diff --git a/src/Module/Api/Mastodon/Accounts/Search.php b/src/Module/Api/Mastodon/Accounts/Search.php index cb565ef73..c31189a42 100644 --- a/src/Module/Api/Mastodon/Accounts/Search.php +++ b/src/Module/Api/Mastodon/Accounts/Search.php @@ -40,7 +40,7 @@ class Search extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); $request = self::getRequest([ diff --git a/src/Module/Api/Mastodon/Accounts/Statuses.php b/src/Module/Api/Mastodon/Accounts/Statuses.php index 07a1e5adc..3b281392b 100644 --- a/src/Module/Api/Mastodon/Accounts/Statuses.php +++ b/src/Module/Api/Mastodon/Accounts/Statuses.php @@ -42,6 +42,8 @@ class Statuses extends BaseApi */ public static function rawContent(array $parameters = []) { + $uid = self::getCurrentUserID(); + if (empty($parameters['id'])) { DI::mstdnError()->UnprocessableEntity(); } @@ -66,8 +68,6 @@ class Statuses extends BaseApi $params = ['order' => ['uri-id' => true], 'limit' => $request['limit']]; - $uid = self::getCurrentUserID(); - if (!$uid) { $condition = ['author-id' => $id, 'private' => [Item::PUBLIC, Item::UNLISTED], 'uid' => 0, 'network' => Protocol::FEDERATED]; diff --git a/src/Module/Api/Mastodon/Accounts/Unblock.php b/src/Module/Api/Mastodon/Accounts/Unblock.php index 14152c458..b1c93ea36 100644 --- a/src/Module/Api/Mastodon/Accounts/Unblock.php +++ b/src/Module/Api/Mastodon/Accounts/Unblock.php @@ -33,7 +33,7 @@ class Unblock extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_FOLLOW); + self::checkAllowedScope(self::SCOPE_FOLLOW); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Accounts/Unfollow.php b/src/Module/Api/Mastodon/Accounts/Unfollow.php index 2d00ea455..447b1cd65 100644 --- a/src/Module/Api/Mastodon/Accounts/Unfollow.php +++ b/src/Module/Api/Mastodon/Accounts/Unfollow.php @@ -33,7 +33,7 @@ class Unfollow extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_FOLLOW); + self::checkAllowedScope(self::SCOPE_FOLLOW); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Accounts/Unmute.php b/src/Module/Api/Mastodon/Accounts/Unmute.php index 4b8111956..bc2e50be9 100644 --- a/src/Module/Api/Mastodon/Accounts/Unmute.php +++ b/src/Module/Api/Mastodon/Accounts/Unmute.php @@ -33,7 +33,7 @@ class Unmute extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_FOLLOW); + self::checkAllowedScope(self::SCOPE_FOLLOW); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Accounts/UpdateCredentials.php b/src/Module/Api/Mastodon/Accounts/UpdateCredentials.php index b2a23cf42..d609cdaae 100644 --- a/src/Module/Api/Mastodon/Accounts/UpdateCredentials.php +++ b/src/Module/Api/Mastodon/Accounts/UpdateCredentials.php @@ -32,7 +32,7 @@ class UpdateCredentials extends BaseApi { public static function patch(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); $data = HTTPInputData::process(); diff --git a/src/Module/Api/Mastodon/Accounts/VerifyCredentials.php b/src/Module/Api/Mastodon/Accounts/VerifyCredentials.php index 84945e1e2..295cbf2af 100644 --- a/src/Module/Api/Mastodon/Accounts/VerifyCredentials.php +++ b/src/Module/Api/Mastodon/Accounts/VerifyCredentials.php @@ -38,7 +38,7 @@ class VerifyCredentials extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); $self = User::getOwnerDataById($uid); diff --git a/src/Module/Api/Mastodon/Announcements.php b/src/Module/Api/Mastodon/Announcements.php index e9445c127..5a414fda1 100644 --- a/src/Module/Api/Mastodon/Announcements.php +++ b/src/Module/Api/Mastodon/Announcements.php @@ -35,7 +35,7 @@ class Announcements extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); // @todo Possibly use the message from the pageheader addon for this System::jsonExit([]); diff --git a/src/Module/Api/Mastodon/Apps/VerifyCredentials.php b/src/Module/Api/Mastodon/Apps/VerifyCredentials.php index eff0b80b3..eee15bc2a 100644 --- a/src/Module/Api/Mastodon/Apps/VerifyCredentials.php +++ b/src/Module/Api/Mastodon/Apps/VerifyCredentials.php @@ -32,7 +32,7 @@ class VerifyCredentials extends BaseApi { public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $application = self::getCurrentApplication(); if (empty($application['id'])) { diff --git a/src/Module/Api/Mastodon/Blocks.php b/src/Module/Api/Mastodon/Blocks.php index 651589f64..d92b6059d 100644 --- a/src/Module/Api/Mastodon/Blocks.php +++ b/src/Module/Api/Mastodon/Blocks.php @@ -37,7 +37,7 @@ class Blocks extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Bookmarks.php b/src/Module/Api/Mastodon/Bookmarks.php index d5e6b7af4..7e298d120 100644 --- a/src/Module/Api/Mastodon/Bookmarks.php +++ b/src/Module/Api/Mastodon/Bookmarks.php @@ -39,7 +39,7 @@ class Bookmarks extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); $request = self::getRequest([ diff --git a/src/Module/Api/Mastodon/Conversations.php b/src/Module/Api/Mastodon/Conversations.php index 3b4496a01..0340478c6 100644 --- a/src/Module/Api/Mastodon/Conversations.php +++ b/src/Module/Api/Mastodon/Conversations.php @@ -33,7 +33,7 @@ class Conversations extends BaseApi { public static function delete(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (!empty($parameters['id'])) { @@ -52,7 +52,7 @@ class Conversations extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); $request = self::getRequest([ diff --git a/src/Module/Api/Mastodon/Conversations/Read.php b/src/Module/Api/Mastodon/Conversations/Read.php index 955ca5c96..c469eea34 100644 --- a/src/Module/Api/Mastodon/Conversations/Read.php +++ b/src/Module/Api/Mastodon/Conversations/Read.php @@ -33,7 +33,7 @@ class Read extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (!empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Favourited.php b/src/Module/Api/Mastodon/Favourited.php index 2b01c95fc..69b102a27 100644 --- a/src/Module/Api/Mastodon/Favourited.php +++ b/src/Module/Api/Mastodon/Favourited.php @@ -40,7 +40,7 @@ class Favourited extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); // @todo provide HTTP link header diff --git a/src/Module/Api/Mastodon/Filters.php b/src/Module/Api/Mastodon/Filters.php index 81794e679..6c1506647 100644 --- a/src/Module/Api/Mastodon/Filters.php +++ b/src/Module/Api/Mastodon/Filters.php @@ -31,7 +31,7 @@ class Filters extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); self::unsupported('post'); } @@ -42,7 +42,7 @@ class Filters extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); System::jsonExit([]); } diff --git a/src/Module/Api/Mastodon/FollowRequests.php b/src/Module/Api/Mastodon/FollowRequests.php index 5b8e9f092..462873845 100644 --- a/src/Module/Api/Mastodon/FollowRequests.php +++ b/src/Module/Api/Mastodon/FollowRequests.php @@ -45,7 +45,7 @@ class FollowRequests extends BaseApi */ public static function post(array $parameters = []) { - self::login(self::SCOPE_FOLLOW); + self::checkAllowedScope(self::SCOPE_FOLLOW); $uid = self::getCurrentUserID(); $introduction = DI::intro()->selectFirst(['id' => $parameters['id'], 'uid' => $uid]); @@ -83,7 +83,7 @@ class FollowRequests extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); $request = self::getRequest([ diff --git a/src/Module/Api/Mastodon/Lists.php b/src/Module/Api/Mastodon/Lists.php index 67db0b81f..8be4207ea 100644 --- a/src/Module/Api/Mastodon/Lists.php +++ b/src/Module/Api/Mastodon/Lists.php @@ -33,8 +33,7 @@ class Lists extends BaseApi { public static function delete(array $parameters = []) { - self::login(self::SCOPE_WRITE); - + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { @@ -54,9 +53,8 @@ class Lists extends BaseApi public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); - - $uid = self::getCurrentUserID(); + self::checkAllowedScope(self::SCOPE_WRITE); + $uid = self::getCurrentUserID(); $request = self::getRequest([ 'title' => '', @@ -96,7 +94,7 @@ class Lists extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Lists/Accounts.php b/src/Module/Api/Mastodon/Lists/Accounts.php index 924f114af..21f85f316 100644 --- a/src/Module/Api/Mastodon/Lists/Accounts.php +++ b/src/Module/Api/Mastodon/Lists/Accounts.php @@ -49,7 +49,7 @@ class Accounts extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Markers.php b/src/Module/Api/Mastodon/Markers.php index dc2949017..a3a3879e0 100644 --- a/src/Module/Api/Mastodon/Markers.php +++ b/src/Module/Api/Mastodon/Markers.php @@ -31,7 +31,7 @@ class Markers extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); self::unsupported('post'); } @@ -42,7 +42,7 @@ class Markers extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); System::jsonExit([]); } diff --git a/src/Module/Api/Mastodon/Media.php b/src/Module/Api/Mastodon/Media.php index f232cd3d5..b93a06288 100644 --- a/src/Module/Api/Mastodon/Media.php +++ b/src/Module/Api/Mastodon/Media.php @@ -34,7 +34,7 @@ class Media extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); Logger::info('Photo post', ['request' => $_REQUEST, 'files' => $_FILES]); @@ -55,7 +55,7 @@ class Media extends BaseApi public static function put(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); $request = self::getRequest([ @@ -85,7 +85,7 @@ class Media extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Mutes.php b/src/Module/Api/Mastodon/Mutes.php index f0c225f18..469f3e0e6 100644 --- a/src/Module/Api/Mastodon/Mutes.php +++ b/src/Module/Api/Mastodon/Mutes.php @@ -37,7 +37,7 @@ class Mutes extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Notifications.php b/src/Module/Api/Mastodon/Notifications.php index 842b85352..cf2a9827c 100644 --- a/src/Module/Api/Mastodon/Notifications.php +++ b/src/Module/Api/Mastodon/Notifications.php @@ -41,7 +41,7 @@ class Notifications extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (!empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Notifications/Clear.php b/src/Module/Api/Mastodon/Notifications/Clear.php index b6961eb53..5471dc24e 100644 --- a/src/Module/Api/Mastodon/Notifications/Clear.php +++ b/src/Module/Api/Mastodon/Notifications/Clear.php @@ -32,7 +32,7 @@ class Clear extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); DBA::update('notification', ['seen' => true], ['uid' => $uid]); diff --git a/src/Module/Api/Mastodon/Notifications/Dismiss.php b/src/Module/Api/Mastodon/Notifications/Dismiss.php index 4c8d3deb9..8900a2d43 100644 --- a/src/Module/Api/Mastodon/Notifications/Dismiss.php +++ b/src/Module/Api/Mastodon/Notifications/Dismiss.php @@ -33,7 +33,7 @@ class Dismiss extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Preferences.php b/src/Module/Api/Mastodon/Preferences.php index f6eef4c79..8ac70e759 100644 --- a/src/Module/Api/Mastodon/Preferences.php +++ b/src/Module/Api/Mastodon/Preferences.php @@ -37,7 +37,7 @@ class Preferences extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); $user = User::getById($uid, ['language', 'allow_cid', 'allow_gid', 'deny_cid', 'deny_gid']); diff --git a/src/Module/Api/Mastodon/Search.php b/src/Module/Api/Mastodon/Search.php index 6bac5779c..4ef4292f8 100644 --- a/src/Module/Api/Mastodon/Search.php +++ b/src/Module/Api/Mastodon/Search.php @@ -43,7 +43,7 @@ class Search extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); $request = self::getRequest([ diff --git a/src/Module/Api/Mastodon/Statuses.php b/src/Module/Api/Mastodon/Statuses.php index 8e13afb2f..77915cab2 100644 --- a/src/Module/Api/Mastodon/Statuses.php +++ b/src/Module/Api/Mastodon/Statuses.php @@ -43,7 +43,7 @@ class Statuses extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); $request = self::getRequest([ @@ -194,7 +194,7 @@ class Statuses extends BaseApi public static function delete(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { @@ -219,10 +219,12 @@ class Statuses extends BaseApi */ public static function rawContent(array $parameters = []) { + $uid = self::getCurrentUserID(); + if (empty($parameters['id'])) { DI::mstdnError()->UnprocessableEntity(); } - System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], self::getCurrentUserID())); + System::jsonExit(DI::mstdnStatus()->createFromUriId($parameters['id'], $uid)); } } diff --git a/src/Module/Api/Mastodon/Statuses/Bookmark.php b/src/Module/Api/Mastodon/Statuses/Bookmark.php index cd59337c3..79be11a4a 100644 --- a/src/Module/Api/Mastodon/Statuses/Bookmark.php +++ b/src/Module/Api/Mastodon/Statuses/Bookmark.php @@ -35,7 +35,7 @@ class Bookmark extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Statuses/Favourite.php b/src/Module/Api/Mastodon/Statuses/Favourite.php index 006e06617..a30ad0fe7 100644 --- a/src/Module/Api/Mastodon/Statuses/Favourite.php +++ b/src/Module/Api/Mastodon/Statuses/Favourite.php @@ -35,7 +35,7 @@ class Favourite extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Statuses/Mute.php b/src/Module/Api/Mastodon/Statuses/Mute.php index ff724ed53..812daff4d 100644 --- a/src/Module/Api/Mastodon/Statuses/Mute.php +++ b/src/Module/Api/Mastodon/Statuses/Mute.php @@ -34,7 +34,7 @@ class Mute extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Statuses/Pin.php b/src/Module/Api/Mastodon/Statuses/Pin.php index 43cc0e0cd..1d5498167 100644 --- a/src/Module/Api/Mastodon/Statuses/Pin.php +++ b/src/Module/Api/Mastodon/Statuses/Pin.php @@ -34,7 +34,7 @@ class Pin extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Statuses/Reblog.php b/src/Module/Api/Mastodon/Statuses/Reblog.php index d0194a312..1af7efb82 100644 --- a/src/Module/Api/Mastodon/Statuses/Reblog.php +++ b/src/Module/Api/Mastodon/Statuses/Reblog.php @@ -37,7 +37,7 @@ class Reblog extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Statuses/Unbookmark.php b/src/Module/Api/Mastodon/Statuses/Unbookmark.php index bf8a3c6e2..f65b07a34 100644 --- a/src/Module/Api/Mastodon/Statuses/Unbookmark.php +++ b/src/Module/Api/Mastodon/Statuses/Unbookmark.php @@ -35,7 +35,7 @@ class Unbookmark extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Statuses/Unfavourite.php b/src/Module/Api/Mastodon/Statuses/Unfavourite.php index 72efdc0a7..b3fee3682 100644 --- a/src/Module/Api/Mastodon/Statuses/Unfavourite.php +++ b/src/Module/Api/Mastodon/Statuses/Unfavourite.php @@ -35,7 +35,7 @@ class Unfavourite extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Statuses/Unmute.php b/src/Module/Api/Mastodon/Statuses/Unmute.php index 531fe6235..ee9b85cc4 100644 --- a/src/Module/Api/Mastodon/Statuses/Unmute.php +++ b/src/Module/Api/Mastodon/Statuses/Unmute.php @@ -34,7 +34,7 @@ class Unmute extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Statuses/Unpin.php b/src/Module/Api/Mastodon/Statuses/Unpin.php index 874be0cc3..1f4195cca 100644 --- a/src/Module/Api/Mastodon/Statuses/Unpin.php +++ b/src/Module/Api/Mastodon/Statuses/Unpin.php @@ -34,7 +34,7 @@ class Unpin extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Statuses/Unreblog.php b/src/Module/Api/Mastodon/Statuses/Unreblog.php index 259ecfd2f..9450e0f41 100644 --- a/src/Module/Api/Mastodon/Statuses/Unreblog.php +++ b/src/Module/Api/Mastodon/Statuses/Unreblog.php @@ -37,7 +37,7 @@ class Unreblog extends BaseApi { public static function post(array $parameters = []) { - self::login(self::SCOPE_WRITE); + self::checkAllowedScope(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Suggestions.php b/src/Module/Api/Mastodon/Suggestions.php index 27c64decd..e0bb75b2d 100644 --- a/src/Module/Api/Mastodon/Suggestions.php +++ b/src/Module/Api/Mastodon/Suggestions.php @@ -37,7 +37,7 @@ class Suggestions extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); $request = self::getRequest([ diff --git a/src/Module/Api/Mastodon/Timelines/Direct.php b/src/Module/Api/Mastodon/Timelines/Direct.php index 050bcbf47..adf677c72 100644 --- a/src/Module/Api/Mastodon/Timelines/Direct.php +++ b/src/Module/Api/Mastodon/Timelines/Direct.php @@ -38,7 +38,7 @@ class Direct extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); $request = self::getRequest([ diff --git a/src/Module/Api/Mastodon/Timelines/Home.php b/src/Module/Api/Mastodon/Timelines/Home.php index 0c955b1c7..63d40e844 100644 --- a/src/Module/Api/Mastodon/Timelines/Home.php +++ b/src/Module/Api/Mastodon/Timelines/Home.php @@ -39,7 +39,7 @@ class Home extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); $request = self::getRequest([ diff --git a/src/Module/Api/Mastodon/Timelines/ListTimeline.php b/src/Module/Api/Mastodon/Timelines/ListTimeline.php index e5bf9d76f..22b2be3bc 100644 --- a/src/Module/Api/Mastodon/Timelines/ListTimeline.php +++ b/src/Module/Api/Mastodon/Timelines/ListTimeline.php @@ -39,7 +39,7 @@ class ListTimeline extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Timelines/Tag.php b/src/Module/Api/Mastodon/Timelines/Tag.php index 74a5bb901..56697f2f5 100644 --- a/src/Module/Api/Mastodon/Timelines/Tag.php +++ b/src/Module/Api/Mastodon/Timelines/Tag.php @@ -40,7 +40,7 @@ class Tag extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(self::SCOPE_READ); + self::checkAllowedScope(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($parameters['hashtag'])) { diff --git a/src/Module/Api/Twitter/ContactEndpoint.php b/src/Module/Api/Twitter/ContactEndpoint.php index 3231d8b13..4641bf813 100644 --- a/src/Module/Api/Twitter/ContactEndpoint.php +++ b/src/Module/Api/Twitter/ContactEndpoint.php @@ -39,9 +39,7 @@ abstract class ContactEndpoint extends BaseApi { parent::init($parameters); - if (!self::login(self::SCOPE_READ)) { - throw new HTTPException\UnauthorizedException(); - } + self::checkAllowedScope(self::SCOPE_READ); } /** @@ -54,7 +52,7 @@ abstract class ContactEndpoint extends BaseApi */ protected static function getUid(int $contact_id = null, string $screen_name = null) { - $uid = self::$current_user_id; + $uid = self::getCurrentUserID(); if ($contact_id || $screen_name) { // screen_name trumps user_id when both are provided @@ -129,7 +127,7 @@ abstract class ContactEndpoint extends BaseApi protected static function ids($rel, int $uid, int $cursor = -1, int $count = self::DEFAULT_COUNT, bool $stringify_ids = false) { $hide_friends = false; - if ($uid != self::$current_user_id) { + if ($uid != self::getCurrentUserID()) { $profile = Profile::getByUID($uid); if (empty($profile)) { throw new HTTPException\NotFoundException(DI::l10n()->t('Profile not found')); diff --git a/src/Module/BaseApi.php b/src/Module/BaseApi.php index 015324569..adad7636a 100644 --- a/src/Module/BaseApi.php +++ b/src/Module/BaseApi.php @@ -24,11 +24,10 @@ namespace Friendica\Module; use Friendica\BaseModule; use Friendica\Core\Logger; use Friendica\Core\System; -use Friendica\Database\Database; -use Friendica\Database\DBA; use Friendica\DI; use Friendica\Network\HTTPException; -use Friendica\Util\DateTimeFormat; +use Friendica\Security\BasicAuth; +use Friendica\Security\OAuth; use Friendica\Util\HTTPInputData; require_once __DIR__ . '/../../include/api.php'; @@ -44,14 +43,6 @@ class BaseApi extends BaseModule * @var string json|xml|rss|atom */ protected static $format = 'json'; - /** - * @var bool|int - */ - protected static $current_user_id; - /** - * @var array - */ - protected static $current_token = []; public static function init(array $parameters = []) { @@ -178,59 +169,19 @@ class BaseApi extends BaseModule } /** - * Log in user via OAuth1 or Simple HTTP Auth. - * - * Simple Auth allow username in form of
user@server, ignoring server part - * - * @param string $scope the requested scope (read, write, follow) - * - * @return bool Was a user authenticated? - * @throws HTTPException\ForbiddenException - * @throws HTTPException\UnauthorizedException - * @throws HTTPException\InternalServerErrorException - * @hook 'authenticate' - * array $addon_auth - * 'username' => username from login form - * 'password' => password from login form - * 'authenticated' => return status, - * 'user_record' => return authenticated user record - */ - protected static function login(string $scope) - { - if (empty(self::$current_user_id)) { - self::$current_token = self::getTokenByBearer(); - if (!empty(self::$current_token['uid'])) { - self::$current_user_id = self::$current_token['uid']; - } else { - self::$current_user_id = 0; - } - } - - if (!empty($scope) && !empty(self::$current_token)) { - if (empty(self::$current_token[$scope])) { - Logger::warning('The requested scope is not allowed', ['scope' => $scope, 'application' => self::$current_token]); - DI::mstdnError()->Forbidden(); - } - } - - if (empty(self::$current_user_id)) { - // The execution stops here if no one is logged in - api_login(DI::app()); - } - - self::$current_user_id = api_user(); - - return (bool)self::$current_user_id; - } - - /** - * Get current application + * Get current application token * * @return array token */ protected static function getCurrentApplication() { - return self::$current_token; + $token = OAuth::getCurrentApplicationToken(); + + if (empty($token)) { + $token = BasicAuth::getCurrentApplicationToken(); + } + + return $token; } /** @@ -238,136 +189,41 @@ class BaseApi extends BaseModule * * @return int User ID */ - public static function getCurrentUserID(bool $nologin = false) + public static function getCurrentUserID() { - if (empty(self::$current_user_id)) { - self::$current_token = self::getTokenByBearer(); - if (!empty(self::$current_token['uid'])) { - self::$current_user_id = self::$current_token['uid']; - } else { - self::$current_user_id = 0; - } + $uid = OAuth::getCurrentUserID(); + + if (empty($uid)) { + $uid = BasicAuth::getCurrentUserID(false); } - if ($nologin) { - return (int)self::$current_user_id; - } - - 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(); - } - - return (int)self::$current_user_id; + return (int)$uid; } /** - * Get the user token via the Bearer token + * Check if the provided scope does exist. + * halts execution on missing scope or when not logged in. * - * @return array User Token + * @param string $scope the requested scope (read, write, follow, push) */ - private static function getTokenByBearer() + public static function checkAllowedScope(string $scope) { - $authorization = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; + $token = self::getCurrentApplication(); - if (substr($authorization, 0, 7) != 'Bearer ') { - return []; + if (empty($token)) { + Logger::notice('Empty application token'); + DI::mstdnError()->Forbidden(); } - $bearer = trim(substr($authorization, 7)); - $condition = ['access_token' => $bearer]; - $token = DBA::selectFirst('application-view', ['uid', 'id', 'name', 'website', 'created_at', 'read', 'write', 'follow', 'push'], $condition); - if (!DBA::isResult($token)) { - Logger::warning('Token not found', $condition); - return []; - } - Logger::debug('Token found', $token); - return $token; - } - - /** - * Get the application record via the proved request header fields - * - * @param string $client_id - * @param string $client_secret - * @param string $redirect_uri - * @return array application record - */ - public static function getApplication(string $client_id, string $client_secret, string $redirect_uri) - { - $condition = ['client_id' => $client_id]; - if (!empty($client_secret)) { - $condition['client_secret'] = $client_secret; - } - if (!empty($redirect_uri)) { - $condition['redirect_uri'] = $redirect_uri; + if (!isset($token[$scope])) { + Logger::warning('The requested scope does not exist', ['scope' => $scope, 'application' => $token]); + DI::mstdnError()->Forbidden(); } - $application = DBA::selectFirst('application', [], $condition); - if (!DBA::isResult($application)) { - Logger::warning('Application not found', $condition); - return []; + if (empty($token[$scope])) { + Logger::warning('The requested scope is not allowed', ['scope' => $scope, 'application' => $token]); + DI::mstdnError()->Forbidden(); } - 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 - * @param string $scope - * @return array application record - */ - public static function createTokenForUser(array $application, int $uid, string $scope) - { - $code = bin2hex(random_bytes(32)); - $access_token = bin2hex(random_bytes(32)); - - $fields = ['application-id' => $application['id'], 'uid' => $uid, 'code' => $code, 'access_token' => $access_token, 'scopes' => $scope, - 'read' => (stripos($scope, self::SCOPE_READ) !== false), - 'write' => (stripos($scope, self::SCOPE_WRITE) !== false), - 'follow' => (stripos($scope, self::SCOPE_FOLLOW) !== false), - 'push' => (stripos($scope, self::SCOPE_PUSH) !== false), - 'created_at' => DateTimeFormat::utcNow(DateTimeFormat::MYSQL)]; - - foreach ([self::SCOPE_READ, self::SCOPE_WRITE, self::SCOPE_WRITE, self::SCOPE_PUSH] as $scope) { - if ($fields[$scope] && !$application[$scope]) { - Logger::warning('Requested token scope is not allowed for the application', ['token' => $fields, 'application' => $application]); - } - } - - if (!DBA::insert('application-token', $fields, Database::INSERT_UPDATE)) { - return []; - } - - return DBA::selectFirst('application-token', [], ['application-id' => $application['id'], 'uid' => $uid]); } /** diff --git a/src/Module/OAuth/Authorize.php b/src/Module/OAuth/Authorize.php index a46c4c7ac..3fcee9246 100644 --- a/src/Module/OAuth/Authorize.php +++ b/src/Module/OAuth/Authorize.php @@ -24,6 +24,7 @@ namespace Friendica\Module\OAuth; use Friendica\Core\Logger; use Friendica\DI; use Friendica\Module\BaseApi; +use Friendica\Security\OAuth; /** * @see https://docs.joinmastodon.org/spec/oauth/ @@ -56,7 +57,7 @@ class Authorize extends BaseApi DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Incomplete request data')); } - $application = self::getApplication($request['client_id'], $request['client_secret'], $request['redirect_uri']); + $application = OAuth::getApplication($request['client_id'], $request['client_secret'], $request['redirect_uri']); if (empty($application)) { DI::mstdnError()->UnprocessableEntity(); } @@ -75,14 +76,14 @@ class Authorize extends BaseApi Logger::info('Already logged in user', ['uid' => $uid]); } - if (!self::existsTokenForUser($application, $uid) && !DI::session()->get('oauth_acknowledge')) { + if (!OAuth::existsTokenForUser($application, $uid) && !DI::session()->get('oauth_acknowledge')) { Logger::info('Redirect to acknowledge'); DI::app()->redirect('oauth/acknowledge?' . http_build_query(['return_path' => $redirect, 'application' => $application['name']])); } DI::session()->remove('oauth_acknowledge'); - $token = self::createTokenForUser($application, $uid, $request['scope']); + $token = OAuth::createTokenForUser($application, $uid, $request['scope']); if (!$token) { DI::mstdnError()->UnprocessableEntity(); } diff --git a/src/Module/OAuth/Token.php b/src/Module/OAuth/Token.php index 780fc7cea..3a8be825f 100644 --- a/src/Module/OAuth/Token.php +++ b/src/Module/OAuth/Token.php @@ -26,6 +26,7 @@ use Friendica\Core\System; use Friendica\Database\DBA; use Friendica\DI; use Friendica\Module\BaseApi; +use Friendica\Security\OAuth; /** * @see https://docs.joinmastodon.org/spec/oauth/ @@ -57,7 +58,7 @@ class Token extends BaseApi DI::mstdnError()->UnprocessableEntity(DI::l10n()->t('Incomplete request data')); } - $application = self::getApplication($request['client_id'], $request['client_secret'], $request['redirect_uri']); + $application = OAuth::getApplication($request['client_id'], $request['client_secret'], $request['redirect_uri']); if (empty($application)) { DI::mstdnError()->UnprocessableEntity(); } @@ -65,7 +66,7 @@ class Token extends BaseApi 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, ''); + $token = OAuth::createTokenForUser($application, 0, ''); } 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", diff --git a/src/Security/BasicAuth.php b/src/Security/BasicAuth.php new file mode 100644 index 000000000..18564d289 --- /dev/null +++ b/src/Security/BasicAuth.php @@ -0,0 +1,88 @@ +. + * + */ + +namespace Friendica\Security; + +use Friendica\Database\DBA; +use Friendica\DI; + +/** + * Authentification via the basic auth method + */ +class BasicAuth +{ + /** + * @var bool|int + */ + protected static $current_user_id = 0; + /** + * @var array + */ + protected static $current_token = []; + + /** + * Get current user id, returns 0 if $login is set to false and not logged in. + * When $login is true, the execution will stop when not logged in. + * + * @param bool $login Perform a login request if "true" + * + * @return int User ID + */ + public static function getCurrentUserID(bool $login) + { + if (empty(self::$current_user_id)) { + api_login(DI::app(), $login); + + self::$current_user_id = api_user(); + } + + return (int)self::$current_user_id; + } + + /** + * Fetch a dummy application token + * + * @return array token + */ + public static function getCurrentApplicationToken() + { + if (empty(self::getCurrentUserID(true))) { + return []; + } + + if (!empty(self::$current_token)) { + return self::$current_token; + } + + self::$current_token = [ + 'uid' => self::$current_user_id, + 'id' => 0, + 'name' => api_source(), + 'website' => '', + 'created_at' => DBA::NULL_DATETIME, + 'read' => true, + 'write' => true, + 'follow' => true, + 'push' => false]; + + return self::$current_token; + } +} diff --git a/src/Security/OAuth.php b/src/Security/OAuth.php new file mode 100644 index 000000000..7210df8c2 --- /dev/null +++ b/src/Security/OAuth.php @@ -0,0 +1,188 @@ +. + * + */ + +namespace Friendica\Security; + +use Friendica\Core\Logger; +use Friendica\Database\Database; +use Friendica\Database\DBA; +use Friendica\Module\BaseApi; +use Friendica\Util\DateTimeFormat; + +/** + * OAuth Server + */ +class OAuth +{ + /** + * @var bool|int + */ + protected static $current_user_id = 0; + /** + * @var array + */ + protected static $current_token = []; + + /** + * Get current user id, returns 0 if not logged in + * + * @return int User ID + */ + public static function getCurrentUserID() + { + if (empty(self::$current_user_id)) { + $token = self::getCurrentApplicationToken(); + if (!empty($token['uid'])) { + self::$current_user_id = $token['uid']; + } else { + self::$current_user_id = 0; + } + } + + return (int)self::$current_user_id; + } + + /** + * Get current application token + * + * @return array token + */ + public static function getCurrentApplicationToken() + { + if (empty(self::$current_token)) { + self::$current_token = self::getTokenByBearer(); + } + + return self::$current_token; + } + + /** + * Get the user token via the Bearer token + * + * @return array User Token + */ + private static function getTokenByBearer() + { + $authorization = $_SERVER['HTTP_AUTHORIZATION'] ?? ''; + + if (substr($authorization, 0, 7) != 'Bearer ') { + return []; + } + + $condition = ['access_token' => trim(substr($authorization, 7))]; + + $token = DBA::selectFirst('application-view', ['uid', 'id', 'name', 'website', 'created_at', 'read', 'write', 'follow', 'push'], $condition); + if (!DBA::isResult($token)) { + Logger::warning('Token not found', $condition); + return []; + } + Logger::debug('Token found', $token); + return $token; + } + + /** + * Get the application record via the provided request header fields + * + * @param string $client_id + * @param string $client_secret + * @param string $redirect_uri + * @return array application record + */ + public static function getApplication(string $client_id, string $client_secret, string $redirect_uri) + { + $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); + return []; + } + 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 + * @param string $scope + * @return array application record + */ + public static function createTokenForUser(array $application, int $uid, string $scope) + { + $code = bin2hex(random_bytes(32)); + $access_token = bin2hex(random_bytes(32)); + + $fields = [ + 'application-id' => $application['id'], + 'uid' => $uid, + 'code' => $code, + 'access_token' => $access_token, + 'scopes' => $scope, + 'read' => (stripos($scope, BaseApi::SCOPE_READ) !== false), + 'write' => (stripos($scope, BaseApi::SCOPE_WRITE) !== false), + 'follow' => (stripos($scope, BaseApi::SCOPE_FOLLOW) !== false), + 'push' => (stripos($scope, BaseApi::SCOPE_PUSH) !== false), + 'created_at' => DateTimeFormat::utcNow(DateTimeFormat::MYSQL)]; + + foreach ([BaseApi::SCOPE_READ, BaseApi::SCOPE_WRITE, BaseApi::SCOPE_WRITE, BaseApi::SCOPE_PUSH] as $scope) { + if ($fields[$scope] && !$application[$scope]) { + Logger::warning('Requested token scope is not allowed for the application', ['token' => $fields, 'application' => $application]); + } + } + + if (!DBA::insert('application-token', $fields, Database::INSERT_UPDATE)) { + return []; + } + + return DBA::selectFirst('application-token', [], ['application-id' => $application['id'], 'uid' => $uid]); + } +}