diff --git a/database.sql b/database.sql index 0dcf9afe8..d080b4158 100644 --- a/database.sql +++ b/database.sql @@ -1,6 +1,6 @@ -- ------------------------------------------ -- Friendica 2021.06-dev (Siberian Iris) --- DB_UPDATE_VERSION 1417 +-- DB_UPDATE_VERSION 1418 -- ------------------------------------------ @@ -378,6 +378,7 @@ CREATE TABLE IF NOT EXISTS `application` ( `read` boolean COMMENT 'Read scope', `write` boolean COMMENT 'Write scope', `follow` boolean COMMENT 'Follow scope', + `push` boolean COMMENT 'Push scope', PRIMARY KEY(`id`), UNIQUE INDEX `client_id` (`client_id`) ) DEFAULT COLLATE utf8mb4_general_ci COMMENT='OAuth application'; @@ -395,6 +396,7 @@ CREATE TABLE IF NOT EXISTS `application-token` ( `read` boolean COMMENT 'Read scope', `write` boolean COMMENT 'Write scope', `follow` boolean COMMENT 'Follow scope', + `push` boolean COMMENT 'Push scope', PRIMARY KEY(`application-id`,`uid`), INDEX `uid_id` (`uid`,`application-id`), FOREIGN KEY (`application-id`) REFERENCES `application` (`id`) ON UPDATE RESTRICT ON DELETE CASCADE, @@ -1525,7 +1527,8 @@ CREATE VIEW `application-view` AS SELECT `application-token`.`scopes` AS `scopes`, `application-token`.`read` AS `read`, `application-token`.`write` AS `write`, - `application-token`.`follow` AS `follow` + `application-token`.`follow` AS `follow`, + `application-token`.`push` AS `push` FROM `application-token` INNER JOIN `application` ON `application-token`.`application-id` = `application`.`id`; diff --git a/src/Factory/Api/Mastodon/Error.php b/src/Factory/Api/Mastodon/Error.php index 086cceef9..4ec8744bf 100644 --- a/src/Factory/Api/Mastodon/Error.php +++ b/src/Factory/Api/Mastodon/Error.php @@ -54,6 +54,15 @@ class Error extends BaseFactory System::jsonError(401, $errorobj->toArray()); } + public function Forbidden(string $error = '') + { + $error = $error ?: DI::l10n()->t('Token is not authorized with a valid user or is missing a required scope'); + $error_description = ''; + $errorobj = New \Friendica\Object\Api\Mastodon\Error($error, $error_description); + + System::jsonError(403, $errorobj->toArray()); + } + public function InternalError(string $error = '') { $error = $error ?: DI::l10n()->t('Internal Server Error'); diff --git a/src/Module/Api/Friendica/Events/Index.php b/src/Module/Api/Friendica/Events/Index.php index 08225682a..3efa1a919 100644 --- a/src/Module/Api/Friendica/Events/Index.php +++ b/src/Module/Api/Friendica/Events/Index.php @@ -35,7 +35,7 @@ class Index extends BaseApi { public static function rawContent(array $parameters = []) { - if (self::login() === false) { + if (self::login(self::SCOPE_READ) === false) { throw new HTTPException\ForbiddenException(); } diff --git a/src/Module/Api/Friendica/Profile/Show.php b/src/Module/Api/Friendica/Profile/Show.php index ae0d1a79d..e550f839c 100644 --- a/src/Module/Api/Friendica/Profile/Show.php +++ b/src/Module/Api/Friendica/Profile/Show.php @@ -37,7 +37,7 @@ class Show extends BaseApi { public static function rawContent(array $parameters = []) { - if (self::login() === false) { + if (self::login(self::SCOPE_READ) === false) { throw new HTTPException\ForbiddenException(); } diff --git a/src/Module/Api/Mastodon/Accounts/Block.php b/src/Module/Api/Mastodon/Accounts/Block.php index edbae8a1d..fa12daaf4 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::login(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 921fac69a..bdd21c737 100644 --- a/src/Module/Api/Mastodon/Accounts/Follow.php +++ b/src/Module/Api/Mastodon/Accounts/Follow.php @@ -33,7 +33,7 @@ class Follow extends BaseApi { public static function post(array $parameters = []) { - self::login(); + self::login(self::SCOPE_FOLLOW); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { @@ -42,6 +42,6 @@ class Follow extends BaseApi $cid = Contact::follow($parameters['id'], self::getCurrentUserID()); - System::jsonExit(DI::mstdnRelationship()->createFromContactId($cid)->toArray()); + 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 7e082edbd..4f560776c 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::login(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 87e9117ea..7edf4e987 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::login(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 5a7d3a840..f92de6cad 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::login(self::SCOPE_READ); System::jsonExit([]); } diff --git a/src/Module/Api/Mastodon/Accounts/Lists.php b/src/Module/Api/Mastodon/Accounts/Lists.php index 6ba7953ab..6a3e87b42 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::login(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 e3975771f..19413bacf 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::login(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 bbb53d93a..1f3dd8d91 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::login(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 a989460a3..c134adf48 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::login(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($_REQUEST['id']) || !is_array($_REQUEST['id'])) { diff --git a/src/Module/Api/Mastodon/Accounts/Search.php b/src/Module/Api/Mastodon/Accounts/Search.php index 77906661d..9f1d0aadf 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::login(self::SCOPE_READ); $uid = self::getCurrentUserID(); // What to search for diff --git a/src/Module/Api/Mastodon/Accounts/Unblock.php b/src/Module/Api/Mastodon/Accounts/Unblock.php index 7de5a4cfb..14152c458 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::login(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 b2efde7b0..2d00ea455 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::login(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 15892cff4..4b8111956 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::login(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 30b190a33..d3f4c15fe 100644 --- a/src/Module/Api/Mastodon/Accounts/UpdateCredentials.php +++ b/src/Module/Api/Mastodon/Accounts/UpdateCredentials.php @@ -31,7 +31,7 @@ class UpdateCredentials extends BaseApi { public static function patch(array $parameters = []) { - self::login(); + self::login(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); $data = Network::postdata(); diff --git a/src/Module/Api/Mastodon/Accounts/VerifyCredentials.php b/src/Module/Api/Mastodon/Accounts/VerifyCredentials.php index facae7259..84945e1e2 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::login(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 80b25bf5c..e9445c127 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::login(self::SCOPE_READ); // @todo Possibly use the message from the pageheader addon for this System::jsonExit([]); diff --git a/src/Module/Api/Mastodon/Apps.php b/src/Module/Api/Mastodon/Apps.php index 8205691dc..c22225160 100644 --- a/src/Module/Api/Mastodon/Apps.php +++ b/src/Module/Api/Mastodon/Apps.php @@ -67,9 +67,10 @@ class Apps extends BaseApi $fields['scopes'] = $scopes; } - $fields['read'] = (stripos($scopes, 'read') !== false); - $fields['write'] = (stripos($scopes, 'write') !== false); - $fields['follow'] = (stripos($scopes, 'follow') !== false); + $fields['read'] = (stripos($scopes, self::SCOPE_READ) !== false); + $fields['write'] = (stripos($scopes, self::SCOPE_WRITE) !== false); + $fields['follow'] = (stripos($scopes, self::SCOPE_FOLLOW) !== false); + $fields['push'] = (stripos($scopes, self::SCOPE_PUSH) !== false); if (!empty($website)) { $fields['website'] = $website; diff --git a/src/Module/Api/Mastodon/Blocks.php b/src/Module/Api/Mastodon/Blocks.php index e93743ac2..b05cb313e 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::login(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 8b03c40eb..88de40d69 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::login(self::SCOPE_READ); $uid = self::getCurrentUserID(); // Maximum number of results to return. Defaults to 20. diff --git a/src/Module/Api/Mastodon/Favourited.php b/src/Module/Api/Mastodon/Favourited.php index 53bd82aab..1c0cf0a34 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::login(self::SCOPE_READ); $uid = self::getCurrentUserID(); // Maximum number of results to return. Defaults to 20. diff --git a/src/Module/Api/Mastodon/FollowRequests.php b/src/Module/Api/Mastodon/FollowRequests.php index 8a59120d3..3c66b4e6c 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::login(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::login(self::SCOPE_READ); $uid = self::getCurrentUserID(); $min_id = $_GET['min_id'] ?? null; diff --git a/src/Module/Api/Mastodon/Lists.php b/src/Module/Api/Mastodon/Lists.php index e655edcb2..496550d4a 100644 --- a/src/Module/Api/Mastodon/Lists.php +++ b/src/Module/Api/Mastodon/Lists.php @@ -33,7 +33,7 @@ class Lists extends BaseApi { public static function delete(array $parameters = []) { - self::login(); + self::login(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); @@ -54,7 +54,7 @@ class Lists extends BaseApi public static function post(array $parameters = []) { - self::login(); + self::login(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); $title = $_REQUEST['title'] ?? ''; @@ -90,7 +90,7 @@ class Lists extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(); + self::login(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 cb2bd208f..1ca2c8359 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::login(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 45ad3927d..dc2949017 100644 --- a/src/Module/Api/Mastodon/Markers.php +++ b/src/Module/Api/Mastodon/Markers.php @@ -31,6 +31,8 @@ class Markers extends BaseApi { public static function post(array $parameters = []) { + self::login(self::SCOPE_WRITE); + self::unsupported('post'); } @@ -40,7 +42,7 @@ class Markers extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(); + self::login(self::SCOPE_READ); System::jsonExit([]); } diff --git a/src/Module/Api/Mastodon/Media.php b/src/Module/Api/Mastodon/Media.php index 82844a6ff..55b8438c2 100644 --- a/src/Module/Api/Mastodon/Media.php +++ b/src/Module/Api/Mastodon/Media.php @@ -33,6 +33,9 @@ class Media extends BaseApi { public static function put(array $parameters = []) { + self::login(self::SCOPE_WRITE); + $uid = self::getCurrentUserID(); + $data = self::getPutData(); self::unsupported('put'); } @@ -43,7 +46,7 @@ class Media extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(); + self::login(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 d49bdad68..9e53da504 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::login(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 e01951722..30e1060d8 100644 --- a/src/Module/Api/Mastodon/Notifications.php +++ b/src/Module/Api/Mastodon/Notifications.php @@ -39,7 +39,7 @@ class Notifications extends BaseApi */ public static function rawContent(array $parameters = []) { - self::login(); + self::login(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 5e0c53da0..c809ad2af 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::login(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); DBA::update('notify', ['seen' => true], ['uid' => $uid]); diff --git a/src/Module/Api/Mastodon/Notifications/Dismiss.php b/src/Module/Api/Mastodon/Notifications/Dismiss.php index e8faa3096..a0f57a405 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::login(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 035357f07..f6eef4c79 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::login(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/Statuses.php b/src/Module/Api/Mastodon/Statuses.php index cb873b83d..e40709fe5 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 post(array $parameters = []) { - self::login(); + self::login(self::SCOPE_WRITE); $uid = self::getCurrentUserID(); $data = self::getJsonPostData(); @@ -190,7 +190,7 @@ class Statuses extends BaseApi public static function delete(array $parameters = []) { - self::login(); + self::login(self::SCOPE_READ); $uid = self::getCurrentUserID(); if (empty($parameters['id'])) { diff --git a/src/Module/Api/Mastodon/Statuses/Bookmark.php b/src/Module/Api/Mastodon/Statuses/Bookmark.php index acdf207a3..cd59337c3 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::login(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 74892d960..006e06617 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::login(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 6a5d16d14..ff724ed53 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::login(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 263780736..43cc0e0cd 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::login(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 cdd788dcf..d0194a312 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::login(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 dd78d8833..bf8a3c6e2 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::login(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 528ef692e..72efdc0a7 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::login(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 26843be6c..531fe6235 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::login(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 d16bfc33e..874be0cc3 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::login(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 1296b7225..259ecfd2f 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::login(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 97cfa11d3..df434d2dc 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::login(self::SCOPE_READ); $uid = self::getCurrentUserID(); // Maximum number of results to return. Defaults to 40. diff --git a/src/Module/Api/Mastodon/Timelines/Home.php b/src/Module/Api/Mastodon/Timelines/Home.php index c46c485fa..9c8cb7a0b 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::login(self::SCOPE_READ); $uid = self::getCurrentUserID(); // Return results older than id diff --git a/src/Module/Api/Mastodon/Timelines/ListTimeline.php b/src/Module/Api/Mastodon/Timelines/ListTimeline.php index 7da16d137..f046cab78 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::login(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 924b76307..b5d0d2140 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::login(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 0e386bf93..3231d8b13 100644 --- a/src/Module/Api/Twitter/ContactEndpoint.php +++ b/src/Module/Api/Twitter/ContactEndpoint.php @@ -39,7 +39,7 @@ abstract class ContactEndpoint extends BaseApi { parent::init($parameters); - if (!self::login()) { + if (!self::login(self::SCOPE_READ)) { throw new HTTPException\UnauthorizedException(); } } diff --git a/src/Module/BaseApi.php b/src/Module/BaseApi.php index 6d70c1e6f..db4531d91 100644 --- a/src/Module/BaseApi.php +++ b/src/Module/BaseApi.php @@ -35,6 +35,11 @@ require_once __DIR__ . '/../../include/api.php'; class BaseApi extends BaseModule { + const SCOPE_READ = 'read'; + const SCOPE_WRITE = 'write'; + const SCOPE_FOLLOW = 'follow'; + const SCOPE_PUSH = 'push'; + /** * @var string json|xml|rss|atom */ @@ -175,6 +180,8 @@ class BaseApi extends BaseModule * * 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 @@ -186,7 +193,7 @@ class BaseApi extends BaseModule * 'authenticated' => return status, * 'user_record' => return authenticated user record */ - protected static function login() + protected static function login(string $scope) { if (empty(self::$current_user_id)) { self::$current_token = self::getTokenByBearer(); @@ -197,6 +204,13 @@ class BaseApi extends BaseModule } } + 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()); @@ -259,7 +273,7 @@ class BaseApi extends BaseModule $bearer = trim(substr($authorization, 7)); $condition = ['access_token' => $bearer]; - $token = DBA::selectFirst('application-view', ['uid', 'id', 'name', 'website', 'created_at', 'read', 'write', 'follow'], $condition); + $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 []; @@ -332,8 +346,18 @@ class BaseApi extends BaseModule $access_token = bin2hex(random_bytes(32)); $fields = ['application-id' => $application['id'], 'uid' => $uid, 'code' => $code, 'access_token' => $access_token, 'scopes' => $scope, - 'read' => (stripos($scope, 'read') !== false), 'write' => (stripos($scope, 'write') !== false), - 'follow' => (stripos($scope, 'follow') !== false), 'created_at' => DateTimeFormat::utcNow(DateTimeFormat::MYSQL)]; + '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 []; } diff --git a/static/dbstructure.config.php b/static/dbstructure.config.php index a074ef0b8..835cb3ff3 100644 --- a/static/dbstructure.config.php +++ b/static/dbstructure.config.php @@ -55,7 +55,7 @@ use Friendica\Database\DBA; if (!defined('DB_UPDATE_VERSION')) { - define('DB_UPDATE_VERSION', 1417); + define('DB_UPDATE_VERSION', 1418); } return [ @@ -439,6 +439,7 @@ return [ "read" => ["type" => "boolean", "comment" => "Read scope"], "write" => ["type" => "boolean", "comment" => "Write scope"], "follow" => ["type" => "boolean", "comment" => "Follow scope"], + "push" => ["type" => "boolean", "comment" => "Push scope"], ], "indexes" => [ "PRIMARY" => ["id"], @@ -457,6 +458,7 @@ return [ "read" => ["type" => "boolean", "comment" => "Read scope"], "write" => ["type" => "boolean", "comment" => "Write scope"], "follow" => ["type" => "boolean", "comment" => "Follow scope"], + "push" => ["type" => "boolean", "comment" => "Push scope"], ], "indexes" => [ "PRIMARY" => ["application-id", "uid"], diff --git a/static/dbview.config.php b/static/dbview.config.php index 324f7f926..488cbceaa 100644 --- a/static/dbview.config.php +++ b/static/dbview.config.php @@ -53,6 +53,7 @@ "read" => ["application-token", "read"], "write" => ["application-token", "write"], "follow" => ["application-token", "follow"], + "push" => ["application-token", "push"], ], "query" => "FROM `application-token` INNER JOIN `application` ON `application-token`.`application-id` = `application`.`id`"