From 1f6ed4f86ab2aa98bb271b40bf381370fab4fdf2 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Thu, 5 Jul 2018 18:31:35 +0200 Subject: [PATCH] Add more granular OAuth scopes (#7929) * Add more granular OAuth scopes * Add human-readable descriptions of the new scopes * Ensure new scopes look good on the app UI * Add tests * Group scopes in screen and color-code dangerous ones * Fix wrong extra scope --- app/controllers/api/base_controller.rb | 4 ++ .../api/v1/accounts/credentials_controller.rb | 4 +- .../accounts/follower_accounts_controller.rb | 2 +- .../accounts/following_accounts_controller.rb | 2 +- .../api/v1/accounts/lists_controller.rb | 2 +- .../v1/accounts/relationships_controller.rb | 2 +- .../api/v1/accounts/search_controller.rb | 2 +- .../api/v1/accounts/statuses_controller.rb | 2 +- app/controllers/api/v1/accounts_controller.rb | 7 ++- app/controllers/api/v1/blocks_controller.rb | 2 +- .../api/v1/domain_blocks_controller.rb | 3 +- .../api/v1/favourites_controller.rb | 2 +- app/controllers/api/v1/filters_controller.rb | 4 +- .../api/v1/follow_requests_controller.rb | 3 +- app/controllers/api/v1/follows_controller.rb | 2 +- .../api/v1/lists/accounts_controller.rb | 4 +- app/controllers/api/v1/lists_controller.rb | 4 +- app/controllers/api/v1/media_controller.rb | 2 +- app/controllers/api/v1/mutes_controller.rb | 2 +- .../api/v1/notifications_controller.rb | 3 +- app/controllers/api/v1/reports_controller.rb | 4 +- app/controllers/api/v1/search_controller.rb | 2 +- .../favourited_by_accounts_controller.rb | 7 +-- .../api/v1/statuses/favourites_controller.rb | 2 +- .../api/v1/statuses/mutes_controller.rb | 2 +- .../api/v1/statuses/pins_controller.rb | 2 +- .../reblogged_by_accounts_controller.rb | 7 +-- .../api/v1/statuses/reblogs_controller.rb | 2 +- app/controllers/api/v1/statuses_controller.rb | 9 +--- .../api/v1/timelines/direct_controller.rb | 2 +- .../api/v1/timelines/home_controller.rb | 2 +- .../api/v1/timelines/list_controller.rb | 2 +- app/helpers/application_helper.rb | 10 ++++ app/javascript/styles/mastodon/forms.scss | 4 ++ .../settings/applications/_fields.html.haml | 17 +++---- config/initializers/doorkeeper.rb | 27 +++++++++- config/locales/doorkeeper.en.yml | 30 +++++++++-- config/locales/simple_form.en.yml | 1 + .../accounts/credentials_controller_spec.rb | 6 ++- .../follower_accounts_controller_spec.rb | 2 +- .../following_accounts_controller_spec.rb | 2 +- .../api/v1/accounts/lists_controller_spec.rb | 2 +- .../accounts/relationships_controller_spec.rb | 2 +- .../api/v1/accounts/search_controller_spec.rb | 2 +- .../v1/accounts/statuses_controller_spec.rb | 2 +- .../api/v1/accounts_controller_spec.rb | 51 ++++++++++++++++--- .../api/v1/blocks_controller_spec.rb | 14 ++++- .../api/v1/domain_blocks_controller_spec.rb | 22 +++++++- .../api/v1/favourites_controller_spec.rb | 2 +- .../api/v1/filter_controller_spec.rb | 8 ++- .../api/v1/follow_requests_controller_spec.rb | 8 ++- .../api/v1/follows_controller_spec.rb | 2 +- .../api/v1/lists/accounts_controller_spec.rb | 7 ++- .../api/v1/lists_controller_spec.rb | 12 ++++- .../api/v1/media_controller_spec.rb | 2 +- .../api/v1/mutes_controller_spec.rb | 2 +- .../api/v1/notifications_controller_spec.rb | 10 +++- .../api/v1/reports_controller_spec.rb | 5 +- .../api/v1/search_controller_spec.rb | 2 +- .../favourited_by_accounts_controller_spec.rb | 2 +- .../v1/statuses/favourites_controller_spec.rb | 2 +- .../api/v1/statuses/mutes_controller_spec.rb | 2 +- .../api/v1/statuses/pins_controller_spec.rb | 2 +- .../reblogged_by_accounts_controller_spec.rb | 2 +- .../v1/statuses/reblogs_controller_spec.rb | 2 +- .../api/v1/statuses_controller_spec.rb | 7 ++- .../api/v1/timelines/home_controller_spec.rb | 2 +- .../api/v1/timelines/list_controller_spec.rb | 2 +- .../api/v2/search_controller_spec.rb | 22 ++++++++ 69 files changed, 295 insertions(+), 105 deletions(-) create mode 100644 spec/controllers/api/v2/search_controller_spec.rb diff --git a/app/controllers/api/base_controller.rb b/app/controllers/api/base_controller.rb index b5c084e145..770a69921a 100644 --- a/app/controllers/api/base_controller.rb +++ b/app/controllers/api/base_controller.rb @@ -78,4 +78,8 @@ class Api::BaseController < ApplicationController def render_empty render json: {}, status: 200 end + + def authorize_if_got_token!(*scopes) + doorkeeper_authorize!(*scopes) if doorkeeper_token + end end diff --git a/app/controllers/api/v1/accounts/credentials_controller.rb b/app/controllers/api/v1/accounts/credentials_controller.rb index 2d0737ee46..dcd41b35c1 100644 --- a/app/controllers/api/v1/accounts/credentials_controller.rb +++ b/app/controllers/api/v1/accounts/credentials_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true class Api::V1::Accounts::CredentialsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read }, except: [:update] - before_action -> { doorkeeper_authorize! :write }, only: [:update] + before_action -> { doorkeeper_authorize! :read, :'read:accounts' }, except: [:update] + before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:update] before_action :require_user! def show diff --git a/app/controllers/api/v1/accounts/follower_accounts_controller.rb b/app/controllers/api/v1/accounts/follower_accounts_controller.rb index 4578cf6ca6..daa35769eb 100644 --- a/app/controllers/api/v1/accounts/follower_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/follower_accounts_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::Accounts::FollowerAccountsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read } + before_action -> { doorkeeper_authorize! :read, :'read:accounts' } before_action :set_account after_action :insert_pagination_headers diff --git a/app/controllers/api/v1/accounts/following_accounts_controller.rb b/app/controllers/api/v1/accounts/following_accounts_controller.rb index ce2bbda855..6be97b87ec 100644 --- a/app/controllers/api/v1/accounts/following_accounts_controller.rb +++ b/app/controllers/api/v1/accounts/following_accounts_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::Accounts::FollowingAccountsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read } + before_action -> { doorkeeper_authorize! :read, :'read:accounts' } before_action :set_account after_action :insert_pagination_headers diff --git a/app/controllers/api/v1/accounts/lists_controller.rb b/app/controllers/api/v1/accounts/lists_controller.rb index a7ba89ce29..72392453c4 100644 --- a/app/controllers/api/v1/accounts/lists_controller.rb +++ b/app/controllers/api/v1/accounts/lists_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::Accounts::ListsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read } + before_action -> { doorkeeper_authorize! :read, :'read:lists' } before_action :require_user! before_action :set_account diff --git a/app/controllers/api/v1/accounts/relationships_controller.rb b/app/controllers/api/v1/accounts/relationships_controller.rb index 70236d1a8b..ab8a0461f5 100644 --- a/app/controllers/api/v1/accounts/relationships_controller.rb +++ b/app/controllers/api/v1/accounts/relationships_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::Accounts::RelationshipsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read } + before_action -> { doorkeeper_authorize! :read, :'read:follows' } before_action :require_user! respond_to :json diff --git a/app/controllers/api/v1/accounts/search_controller.rb b/app/controllers/api/v1/accounts/search_controller.rb index 7649da4339..91c9f15472 100644 --- a/app/controllers/api/v1/accounts/search_controller.rb +++ b/app/controllers/api/v1/accounts/search_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::Accounts::SearchController < Api::BaseController - before_action -> { doorkeeper_authorize! :read } + before_action -> { doorkeeper_authorize! :read, :'read:accounts' } before_action :require_user! respond_to :json diff --git a/app/controllers/api/v1/accounts/statuses_controller.rb b/app/controllers/api/v1/accounts/statuses_controller.rb index c40155cb56..06fa6c7623 100644 --- a/app/controllers/api/v1/accounts/statuses_controller.rb +++ b/app/controllers/api/v1/accounts/statuses_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::Accounts::StatusesController < Api::BaseController - before_action -> { doorkeeper_authorize! :read } + before_action -> { doorkeeper_authorize! :read, :'read:statuses' } before_action :set_account after_action :insert_pagination_headers diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index b7133ca8e5..1d5372a8cd 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -1,8 +1,11 @@ # frozen_string_literal: true class Api::V1::AccountsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read }, except: [:follow, :unfollow, :block, :unblock, :mute, :unmute] - before_action -> { doorkeeper_authorize! :follow }, only: [:follow, :unfollow, :block, :unblock, :mute, :unmute] + before_action -> { authorize_if_got_token! :read, :'read:accounts' }, except: [:follow, :unfollow, :block, :unblock, :mute, :unmute] + before_action -> { doorkeeper_authorize! :follow, :'write:follows' }, only: [:follow, :unfollow] + before_action -> { doorkeeper_authorize! :follow, :'write:mutes' }, only: [:mute, :unmute] + before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, only: [:block, :unblock] + before_action :require_user!, except: [:show] before_action :set_account before_action :check_account_suspension, only: [:show] diff --git a/app/controllers/api/v1/blocks_controller.rb b/app/controllers/api/v1/blocks_controller.rb index a397013407..99c53d59af 100644 --- a/app/controllers/api/v1/blocks_controller.rb +++ b/app/controllers/api/v1/blocks_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::BlocksController < Api::BaseController - before_action -> { doorkeeper_authorize! :follow } + before_action -> { doorkeeper_authorize! :follow, :'read:blocks' } before_action :require_user! after_action :insert_pagination_headers diff --git a/app/controllers/api/v1/domain_blocks_controller.rb b/app/controllers/api/v1/domain_blocks_controller.rb index e55d622c3a..af9e7a20f7 100644 --- a/app/controllers/api/v1/domain_blocks_controller.rb +++ b/app/controllers/api/v1/domain_blocks_controller.rb @@ -3,7 +3,8 @@ class Api::V1::DomainBlocksController < Api::BaseController BLOCK_LIMIT = 100 - before_action -> { doorkeeper_authorize! :follow } + before_action -> { doorkeeper_authorize! :follow, :'read:blocks' }, only: :show + before_action -> { doorkeeper_authorize! :follow, :'write:blocks' }, except: :show before_action :require_user! after_action :insert_pagination_headers, only: :show diff --git a/app/controllers/api/v1/favourites_controller.rb b/app/controllers/api/v1/favourites_controller.rb index b4265ed343..ab5204355c 100644 --- a/app/controllers/api/v1/favourites_controller.rb +++ b/app/controllers/api/v1/favourites_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::FavouritesController < Api::BaseController - before_action -> { doorkeeper_authorize! :read } + before_action -> { doorkeeper_authorize! :read, :'read:favourites' } before_action :require_user! after_action :insert_pagination_headers diff --git a/app/controllers/api/v1/filters_controller.rb b/app/controllers/api/v1/filters_controller.rb index c89722b853..02efd323ba 100644 --- a/app/controllers/api/v1/filters_controller.rb +++ b/app/controllers/api/v1/filters_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true class Api::V1::FiltersController < Api::BaseController - before_action -> { doorkeeper_authorize! :read }, only: [:index, :show] - before_action -> { doorkeeper_authorize! :write }, except: [:index, :show] + before_action -> { doorkeeper_authorize! :read, :'read:filters' }, only: [:index, :show] + before_action -> { doorkeeper_authorize! :write, :'write:filters' }, except: [:index, :show] before_action :require_user! before_action :set_filters, only: :index before_action :set_filter, only: [:show, :update, :destroy] diff --git a/app/controllers/api/v1/follow_requests_controller.rb b/app/controllers/api/v1/follow_requests_controller.rb index d5c7c565a0..313fe2f81c 100644 --- a/app/controllers/api/v1/follow_requests_controller.rb +++ b/app/controllers/api/v1/follow_requests_controller.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true class Api::V1::FollowRequestsController < Api::BaseController - before_action -> { doorkeeper_authorize! :follow } + before_action -> { doorkeeper_authorize! :follow, :'read:follows' }, only: :index + before_action -> { doorkeeper_authorize! :follow, :'write:follows' }, except: :index before_action :require_user! after_action :insert_pagination_headers, only: :index diff --git a/app/controllers/api/v1/follows_controller.rb b/app/controllers/api/v1/follows_controller.rb index 5a2b2f32f3..5420c05336 100644 --- a/app/controllers/api/v1/follows_controller.rb +++ b/app/controllers/api/v1/follows_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::FollowsController < Api::BaseController - before_action -> { doorkeeper_authorize! :follow } + before_action -> { doorkeeper_authorize! :follow, :'write:follows' } before_action :require_user! respond_to :json diff --git a/app/controllers/api/v1/lists/accounts_controller.rb b/app/controllers/api/v1/lists/accounts_controller.rb index f2bded851c..19de567321 100644 --- a/app/controllers/api/v1/lists/accounts_controller.rb +++ b/app/controllers/api/v1/lists/accounts_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true class Api::V1::Lists::AccountsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read }, only: [:show] - before_action -> { doorkeeper_authorize! :write }, except: [:show] + before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:show] + before_action -> { doorkeeper_authorize! :write, :'write:lists' }, except: [:show] before_action :require_user! before_action :set_list diff --git a/app/controllers/api/v1/lists_controller.rb b/app/controllers/api/v1/lists_controller.rb index 180a91d81b..b42b8b9710 100644 --- a/app/controllers/api/v1/lists_controller.rb +++ b/app/controllers/api/v1/lists_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true class Api::V1::ListsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read }, only: [:index, :show] - before_action -> { doorkeeper_authorize! :write }, except: [:index, :show] + before_action -> { doorkeeper_authorize! :read, :'read:lists' }, only: [:index, :show] + before_action -> { doorkeeper_authorize! :write, :'write:lists' }, except: [:index, :show] before_action :require_user! before_action :set_list, except: [:index, :create] diff --git a/app/controllers/api/v1/media_controller.rb b/app/controllers/api/v1/media_controller.rb index d4e6337e76..aaa93b6158 100644 --- a/app/controllers/api/v1/media_controller.rb +++ b/app/controllers/api/v1/media_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::MediaController < Api::BaseController - before_action -> { doorkeeper_authorize! :write } + before_action -> { doorkeeper_authorize! :write, :'write:media' } before_action :require_user! include ObfuscateFilename diff --git a/app/controllers/api/v1/mutes_controller.rb b/app/controllers/api/v1/mutes_controller.rb index c457408ba7..faa7d16cd9 100644 --- a/app/controllers/api/v1/mutes_controller.rb +++ b/app/controllers/api/v1/mutes_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::MutesController < Api::BaseController - before_action -> { doorkeeper_authorize! :follow } + before_action -> { doorkeeper_authorize! :follow, :'read:mutes' } before_action :require_user! after_action :insert_pagination_headers diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb index ebbe0b292e..593c8f9a9c 100644 --- a/app/controllers/api/v1/notifications_controller.rb +++ b/app/controllers/api/v1/notifications_controller.rb @@ -1,7 +1,8 @@ # frozen_string_literal: true class Api::V1::NotificationsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read } + before_action -> { doorkeeper_authorize! :read, :'read:notifications' }, except: [:clear, :dismiss] + before_action -> { doorkeeper_authorize! :write, :'write:notifications' }, only: [:clear, :dismiss] before_action :require_user! after_action :insert_pagination_headers, only: :index diff --git a/app/controllers/api/v1/reports_controller.rb b/app/controllers/api/v1/reports_controller.rb index f5095e0730..a954101cb8 100644 --- a/app/controllers/api/v1/reports_controller.rb +++ b/app/controllers/api/v1/reports_controller.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true class Api::V1::ReportsController < Api::BaseController - before_action -> { doorkeeper_authorize! :read }, except: [:create] - before_action -> { doorkeeper_authorize! :write }, only: [:create] + before_action -> { doorkeeper_authorize! :read, :'read:reports' }, except: [:create] + before_action -> { doorkeeper_authorize! :write, :'write:reports' }, only: [:create] before_action :require_user! respond_to :json diff --git a/app/controllers/api/v1/search_controller.rb b/app/controllers/api/v1/search_controller.rb index 05754d0f24..dc1a37599e 100644 --- a/app/controllers/api/v1/search_controller.rb +++ b/app/controllers/api/v1/search_controller.rb @@ -5,7 +5,7 @@ class Api::V1::SearchController < Api::BaseController RESULTS_LIMIT = 5 - before_action -> { doorkeeper_authorize! :read } + before_action -> { doorkeeper_authorize! :read, :'read:search' } before_action :require_user! respond_to :json diff --git a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb index 3fe304153e..8f4070bc78 100644 --- a/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb +++ b/app/controllers/api/v1/statuses/favourited_by_accounts_controller.rb @@ -3,7 +3,7 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController include Authorization - before_action :authorize_if_got_token + before_action -> { authorize_if_got_token! :read, :'read:accounts' } before_action :set_status after_action :insert_pagination_headers @@ -71,11 +71,6 @@ class Api::V1::Statuses::FavouritedByAccountsController < Api::BaseController raise ActiveRecord::RecordNotFound end - def authorize_if_got_token - request_token = Doorkeeper::OAuth::Token.from_request(request, *Doorkeeper.configuration.access_token_methods) - doorkeeper_authorize! :read if request_token - end - def pagination_params(core_params) params.slice(:limit).permit(:limit).merge(core_params) end diff --git a/app/controllers/api/v1/statuses/favourites_controller.rb b/app/controllers/api/v1/statuses/favourites_controller.rb index 35f8a48cd6..cceee90609 100644 --- a/app/controllers/api/v1/statuses/favourites_controller.rb +++ b/app/controllers/api/v1/statuses/favourites_controller.rb @@ -3,7 +3,7 @@ class Api::V1::Statuses::FavouritesController < Api::BaseController include Authorization - before_action -> { doorkeeper_authorize! :write } + before_action -> { doorkeeper_authorize! :write, :'write:favourites' } before_action :require_user! respond_to :json diff --git a/app/controllers/api/v1/statuses/mutes_controller.rb b/app/controllers/api/v1/statuses/mutes_controller.rb index a4bf0acdd2..b02469b4f4 100644 --- a/app/controllers/api/v1/statuses/mutes_controller.rb +++ b/app/controllers/api/v1/statuses/mutes_controller.rb @@ -3,7 +3,7 @@ class Api::V1::Statuses::MutesController < Api::BaseController include Authorization - before_action -> { doorkeeper_authorize! :write } + before_action -> { doorkeeper_authorize! :write, :'write:mutes' } before_action :require_user! before_action :set_status before_action :set_conversation diff --git a/app/controllers/api/v1/statuses/pins_controller.rb b/app/controllers/api/v1/statuses/pins_controller.rb index 54f8be667d..4118a8ce4e 100644 --- a/app/controllers/api/v1/statuses/pins_controller.rb +++ b/app/controllers/api/v1/statuses/pins_controller.rb @@ -3,7 +3,7 @@ class Api::V1::Statuses::PinsController < Api::BaseController include Authorization - before_action -> { doorkeeper_authorize! :write } + before_action -> { doorkeeper_authorize! :write, :'write:accounts' } before_action :require_user! before_action :set_status diff --git a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb index b065db2c75..93b83ce485 100644 --- a/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb +++ b/app/controllers/api/v1/statuses/reblogged_by_accounts_controller.rb @@ -3,7 +3,7 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController include Authorization - before_action :authorize_if_got_token + before_action -> { authorize_if_got_token! :read, :'read:accounts' } before_action :set_status after_action :insert_pagination_headers @@ -68,11 +68,6 @@ class Api::V1::Statuses::RebloggedByAccountsController < Api::BaseController raise ActiveRecord::RecordNotFound end - def authorize_if_got_token - request_token = Doorkeeper::OAuth::Token.from_request(request, *Doorkeeper.configuration.access_token_methods) - doorkeeper_authorize! :read if request_token - end - def pagination_params(core_params) params.slice(:limit).permit(:limit).merge(core_params) end diff --git a/app/controllers/api/v1/statuses/reblogs_controller.rb b/app/controllers/api/v1/statuses/reblogs_controller.rb index 634af474f9..04847a6b76 100644 --- a/app/controllers/api/v1/statuses/reblogs_controller.rb +++ b/app/controllers/api/v1/statuses/reblogs_controller.rb @@ -3,7 +3,7 @@ class Api::V1::Statuses::ReblogsController < Api::BaseController include Authorization - before_action -> { doorkeeper_authorize! :write } + before_action -> { doorkeeper_authorize! :write, :'write:statuses' } before_action :require_user! respond_to :json diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb index 289d910454..c6925d4629 100644 --- a/app/controllers/api/v1/statuses_controller.rb +++ b/app/controllers/api/v1/statuses_controller.rb @@ -3,8 +3,8 @@ class Api::V1::StatusesController < Api::BaseController include Authorization - before_action :authorize_if_got_token, except: [:create, :destroy] - before_action -> { doorkeeper_authorize! :write }, only: [:create, :destroy] + before_action -> { authorize_if_got_token! :read, :'read:statuses' }, except: [:create, :destroy] + before_action -> { doorkeeper_authorize! :write, :'write:statuses' }, only: [:create, :destroy] before_action :require_user!, except: [:show, :context, :card] before_action :set_status, only: [:show, :context, :card] @@ -84,9 +84,4 @@ class Api::V1::StatusesController < Api::BaseController def pagination_params(core_params) params.slice(:limit).permit(:limit).merge(core_params) end - - def authorize_if_got_token - request_token = Doorkeeper::OAuth::Token.from_request(request, *Doorkeeper.configuration.access_token_methods) - doorkeeper_authorize! :read if request_token - end end diff --git a/app/controllers/api/v1/timelines/direct_controller.rb b/app/controllers/api/v1/timelines/direct_controller.rb index ef64078be8..d8a76d153a 100644 --- a/app/controllers/api/v1/timelines/direct_controller.rb +++ b/app/controllers/api/v1/timelines/direct_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::Timelines::DirectController < Api::BaseController - before_action -> { doorkeeper_authorize! :read }, only: [:show] + before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: [:show] before_action :require_user!, only: [:show] after_action :insert_pagination_headers, unless: -> { @statuses.empty? } diff --git a/app/controllers/api/v1/timelines/home_controller.rb b/app/controllers/api/v1/timelines/home_controller.rb index cde4e8420c..4412aaaa39 100644 --- a/app/controllers/api/v1/timelines/home_controller.rb +++ b/app/controllers/api/v1/timelines/home_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::Timelines::HomeController < Api::BaseController - before_action -> { doorkeeper_authorize! :read }, only: [:show] + before_action -> { doorkeeper_authorize! :read, :'read:statuses' }, only: [:show] before_action :require_user!, only: [:show] after_action :insert_pagination_headers, unless: -> { @statuses.empty? } diff --git a/app/controllers/api/v1/timelines/list_controller.rb b/app/controllers/api/v1/timelines/list_controller.rb index 06d596c08a..cfc5f3b5e4 100644 --- a/app/controllers/api/v1/timelines/list_controller.rb +++ b/app/controllers/api/v1/timelines/list_controller.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class Api::V1::Timelines::ListController < Api::BaseController - before_action -> { doorkeeper_authorize! :read } + before_action -> { doorkeeper_authorize! :read, :'read:lists' } before_action :require_user! before_action :set_list before_action :set_statuses diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 95863ab1f0..327901e4e2 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,6 +1,12 @@ # frozen_string_literal: true module ApplicationHelper + DANGEROUS_SCOPES = %w( + read + write + follow + ).freeze + def active_nav_class(path) current_page?(path) ? 'active' : '' end @@ -43,6 +49,10 @@ module ApplicationHelper Rails.env.production? ? site_title : "#{site_title} (Dev)" end + def class_for_scope(scope) + 'scope-danger' if DANGEROUS_SCOPES.include?(scope.to_s) + end + def can?(action, record) return false if record.nil? policy(record).public_send("#{action}?") diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss index e4fd6c1f1a..458eb86e98 100644 --- a/app/javascript/styles/mastodon/forms.scss +++ b/app/javascript/styles/mastodon/forms.scss @@ -612,3 +612,7 @@ code { display: block; } } + +.scope-danger { + color: $warning-red; +} diff --git a/app/views/settings/applications/_fields.html.haml b/app/views/settings/applications/_fields.html.haml index b21f3cca62..db90df3491 100644 --- a/app/views/settings/applications/_fields.html.haml +++ b/app/views/settings/applications/_fields.html.haml @@ -8,14 +8,9 @@ %p.hint= t('doorkeeper.applications.help.native_redirect_uri', native_redirect_uri: Doorkeeper.configuration.native_redirect_uri) .field-group - = f.input :scopes, - label: t('activerecord.attributes.doorkeeper/application.scopes'), - collection: Doorkeeper.configuration.scopes, - wrapper: :with_label, - include_blank: false, - label_method: lambda { |scope| safe_join([scope, content_tag(:span, t("doorkeeper.scopes.#{scope}"), class: 'hint')]) }, - selected: f.object.scopes.all, - required: false, - as: :check_boxes, - collection_wrapper_tag: 'ul', - item_wrapper_tag: 'li' + .input.with_block_label + %label= t('activerecord.attributes.doorkeeper/application.scopes') + %span.hint= t('simple_form.hints.defaults.scopes') + + - Doorkeeper.configuration.scopes.group_by { |s| s.split(':').first }.each do |k, v| + = f.input :scopes, label: false, hint: false, collection: v.sort, wrapper: :with_block_label, include_blank: false, label_method: lambda { |scope| safe_join([content_tag(:samp, scope, class: class_for_scope(scope)), content_tag(:span, t("doorkeeper.scopes.#{scope}"), class: 'hint')]) }, selected: f.object.scopes.all, required: false, as: :check_boxes, collection_wrapper_tag: 'ul', item_wrapper_tag: 'li' diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index 4695538030..fe2490b326 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -55,7 +55,32 @@ Doorkeeper.configure do # For more information go to # https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes default_scopes :read - optional_scopes :write, :follow, :push + optional_scopes :write, + :'write:accounts', + :'write:blocks', + :'write:favourites', + :'write:filters', + :'write:follows', + :'write:lists', + :'write:media', + :'write:mutes', + :'write:notifications', + :'write:reports', + :'write:statuses', + :read, + :'read:accounts', + :'read:blocks', + :'read:favourites', + :'read:filters', + :'read:follows', + :'read:lists', + :'read:mutes', + :'read:notifications', + :'read:reports', + :'read:search', + :'read:statuses', + :follow, + :push # Change the way client credentials are retrieved from the request object. # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml index eca1fc675f..f1fe03716a 100644 --- a/config/locales/doorkeeper.en.yml +++ b/config/locales/doorkeeper.en.yml @@ -114,7 +114,29 @@ en: application: title: OAuth authorization required scopes: - follow: follow, block, unblock and unfollow accounts - push: receive push notifications for your account - read: read your account's data - write: post on your behalf + follow: modify account relationships + push: receive your push notifications + read: read all your account's data + read:accounts: see accounts information + read:blocks: see your blocks + read:favourites: see your favourites + read:filters: see your filters + read:follows: see your follows + read:lists: see your lists + read:mutes: see your mutes + read:notifications: see your notifications + read:reports: see your reports + read:search: search on your behalf + read:statuses: see all statuses + write: modify all your account's data + write:accounts: modify your profile + write:blocks: block accounts and domains + write:favourites: favourite statuses + write:filters: create filters + write:follows: follow people + write:lists: create lists + write:media: upload media files + write:mutes: mute people and conversations + write:notifications: clear your notifications + write:reports: report other people + write:statuses: publish statuses diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 59133ea733..49d94bcde9 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -20,6 +20,7 @@ en: one: 1 character left other: %{count} characters left phrase: Will be matched regardless of casing in text or content warning of a toot + scopes: Which APIs the application will be allowed to access. If you select a top-level scope, you don't need to select individual ones. setting_default_language: The language of your toots can be detected automatically, but it's not always accurate setting_hide_network: Who you follow and who follows you will not be shown on your profile setting_noindex: Affects your public profile and status pages diff --git a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb index 9a52fd14c5..7276698863 100644 --- a/spec/controllers/api/v1/accounts/credentials_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/credentials_controller_spec.rb @@ -4,7 +4,7 @@ describe Api::V1::Accounts::CredentialsController do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read write') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } context 'with an oauth token' do before do @@ -12,6 +12,8 @@ describe Api::V1::Accounts::CredentialsController do end describe 'GET #show' do + let(:scopes) { 'read:accounts' } + it 'returns http success' do get :show expect(response).to have_http_status(200) @@ -19,6 +21,8 @@ describe Api::V1::Accounts::CredentialsController do end describe 'PATCH #update' do + let(:scopes) { 'write:accounts' } + describe 'with valid data' do before do allow(ActivityPub::UpdateDistributionWorker).to receive(:perform_async) diff --git a/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb b/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb index b47af49631..75e0570e92 100644 --- a/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/follower_accounts_controller_spec.rb @@ -4,7 +4,7 @@ describe Api::V1::Accounts::FollowerAccountsController do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } before do Fabricate(:follow, target_account: user.account) diff --git a/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb b/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb index 29fd7cd5b7..7f7105ad3a 100644 --- a/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/following_accounts_controller_spec.rb @@ -4,7 +4,7 @@ describe Api::V1::Accounts::FollowingAccountsController do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } before do Fabricate(:follow, account: user.account) diff --git a/spec/controllers/api/v1/accounts/lists_controller_spec.rb b/spec/controllers/api/v1/accounts/lists_controller_spec.rb index df9fe0e34c..baafea8e6b 100644 --- a/spec/controllers/api/v1/accounts/lists_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/lists_controller_spec.rb @@ -4,7 +4,7 @@ describe Api::V1::Accounts::ListsController do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:lists') } let(:account) { Fabricate(:account) } let(:list) { Fabricate(:list, account: user.account) } diff --git a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb index 7e350da7e5..fe715ff625 100644 --- a/spec/controllers/api/v1/accounts/relationships_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/relationships_controller_spec.rb @@ -4,7 +4,7 @@ describe Api::V1::Accounts::RelationshipsController do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:follows') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/accounts/search_controller_spec.rb b/spec/controllers/api/v1/accounts/search_controller_spec.rb index dbc4b9f3e6..8ff2b17dee 100644 --- a/spec/controllers/api/v1/accounts/search_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/search_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::Accounts::SearchController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:accounts') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb index 09bb469373..693cd1ac66 100644 --- a/spec/controllers/api/v1/accounts/statuses_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/statuses_controller_spec.rb @@ -4,7 +4,7 @@ describe Api::V1::Accounts::StatusesController do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/accounts_controller_spec.rb b/spec/controllers/api/v1/accounts_controller_spec.rb index 7a9e0f8e41..3e54e88a5b 100644 --- a/spec/controllers/api/v1/accounts_controller_spec.rb +++ b/spec/controllers/api/v1/accounts_controller_spec.rb @@ -3,21 +3,38 @@ require 'rails_helper' RSpec.describe Api::V1::AccountsController, type: :controller do render_views - let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow read') } + let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } + let(:scopes) { '' } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } before do allow(controller).to receive(:doorkeeper_token) { token } end - describe 'GET #show' do - it 'returns http success' do - get :show, params: { id: user.account.id } - expect(response).to have_http_status(200) + shared_examples 'forbidden for wrong scope' do |wrong_scope| + let(:scopes) { wrong_scope } + + it 'returns http forbidden' do + expect(response).to have_http_status(403) end end + describe 'GET #show' do + let(:scopes) { 'read:accounts' } + + before do + get :show, params: { id: user.account.id } + end + + it 'returns http success' do + expect(response).to have_http_status(200) + end + + it_behaves_like 'forbidden for wrong scope', 'write:statuses' + end + describe 'POST #follow' do + let(:scopes) { 'write:follows' } let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob', locked: locked)).account } before do @@ -41,6 +58,8 @@ RSpec.describe Api::V1::AccountsController, type: :controller do it 'creates a following relation between user and target user' do expect(user.account.following?(other_account)).to be true end + + it_behaves_like 'forbidden for wrong scope', 'read:accounts' end context 'with locked account' do @@ -60,10 +79,13 @@ RSpec.describe Api::V1::AccountsController, type: :controller do it 'creates a follow request relation between user and target user' do expect(user.account.requested?(other_account)).to be true end + + it_behaves_like 'forbidden for wrong scope', 'read:accounts' end end describe 'POST #unfollow' do + let(:scopes) { 'write:follows' } let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account } before do @@ -78,9 +100,12 @@ RSpec.describe Api::V1::AccountsController, type: :controller do it 'removes the following relation between user and target user' do expect(user.account.following?(other_account)).to be false end + + it_behaves_like 'forbidden for wrong scope', 'read:accounts' end describe 'POST #block' do + let(:scopes) { 'write:blocks' } let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account } before do @@ -99,9 +124,12 @@ RSpec.describe Api::V1::AccountsController, type: :controller do it 'creates a blocking relation' do expect(user.account.blocking?(other_account)).to be true end + + it_behaves_like 'forbidden for wrong scope', 'read:accounts' end describe 'POST #unblock' do + let(:scopes) { 'write:blocks' } let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account } before do @@ -116,9 +144,12 @@ RSpec.describe Api::V1::AccountsController, type: :controller do it 'removes the blocking relation between user and target user' do expect(user.account.blocking?(other_account)).to be false end + + it_behaves_like 'forbidden for wrong scope', 'read:accounts' end describe 'POST #mute' do + let(:scopes) { 'write:mutes' } let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account } before do @@ -141,9 +172,12 @@ RSpec.describe Api::V1::AccountsController, type: :controller do it 'mutes notifications' do expect(user.account.muting_notifications?(other_account)).to be true end + + it_behaves_like 'forbidden for wrong scope', 'read:accounts' end describe 'POST #mute with notifications set to false' do + let(:scopes) { 'write:mutes' } let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account } before do @@ -166,9 +200,12 @@ RSpec.describe Api::V1::AccountsController, type: :controller do it 'does not mute notifications' do expect(user.account.muting_notifications?(other_account)).to be false end + + it_behaves_like 'forbidden for wrong scope', 'read:accounts' end describe 'POST #unmute' do + let(:scopes) { 'write:mutes' } let(:other_account) { Fabricate(:user, email: 'bob@example.com', account: Fabricate(:account, username: 'bob')).account } before do @@ -183,5 +220,7 @@ RSpec.describe Api::V1::AccountsController, type: :controller do it 'removes the muting relation between user and target user' do expect(user.account.muting?(other_account)).to be false end + + it_behaves_like 'forbidden for wrong scope', 'read:accounts' end end diff --git a/spec/controllers/api/v1/blocks_controller_spec.rb b/spec/controllers/api/v1/blocks_controller_spec.rb index eff5fb9daa..818f76c923 100644 --- a/spec/controllers/api/v1/blocks_controller_spec.rb +++ b/spec/controllers/api/v1/blocks_controller_spec.rb @@ -3,8 +3,9 @@ require 'rails_helper' RSpec.describe Api::V1::BlocksController, type: :controller do render_views - let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow') } + let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } + let(:scopes) { 'read:blocks' } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } before { allow(controller).to receive(:doorkeeper_token) { token } } @@ -49,5 +50,14 @@ RSpec.describe Api::V1::BlocksController, type: :controller do get :index expect(response).to have_http_status(200) end + + context 'with wrong scopes' do + let(:scopes) { 'write:blocks' } + + it 'returns http forbidden' do + get :index + expect(response).to have_http_status(403) + end + end end end diff --git a/spec/controllers/api/v1/domain_blocks_controller_spec.rb b/spec/controllers/api/v1/domain_blocks_controller_spec.rb index bae4612a28..6a7a35c7a5 100644 --- a/spec/controllers/api/v1/domain_blocks_controller_spec.rb +++ b/spec/controllers/api/v1/domain_blocks_controller_spec.rb @@ -4,14 +4,24 @@ RSpec.describe Api::V1::DomainBlocksController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } before do user.account.block_domain!('example.com') allow(controller).to receive(:doorkeeper_token) { token } end + shared_examples 'forbidden for wrong scope' do |wrong_scope| + let(:scopes) { wrong_scope } + + it 'returns http forbidden' do + expect(response).to have_http_status(403) + end + end + describe 'GET #show' do + let(:scopes) { 'read:blocks' } + before do get :show, params: { limit: 1 } end @@ -23,9 +33,13 @@ RSpec.describe Api::V1::DomainBlocksController, type: :controller do it 'returns blocked domains' do expect(body_as_json.first).to eq 'example.com' end + + it_behaves_like 'forbidden for wrong scope', 'write:statuses' end describe 'POST #create' do + let(:scopes) { 'write:blocks' } + before do post :create, params: { domain: 'example.org' } end @@ -37,9 +51,13 @@ RSpec.describe Api::V1::DomainBlocksController, type: :controller do it 'creates a domain block' do expect(user.account.domain_blocking?('example.org')).to be true end + + it_behaves_like 'forbidden for wrong scope', 'write:statuses' end describe 'DELETE #destroy' do + let(:scopes) { 'write:blocks' } + before do delete :destroy, params: { domain: 'example.com' } end @@ -51,5 +69,7 @@ RSpec.describe Api::V1::DomainBlocksController, type: :controller do it 'deletes a domain block' do expect(user.account.domain_blocking?('example.com')).to be false end + + it_behaves_like 'forbidden for wrong scope', 'write:statuses' end end diff --git a/spec/controllers/api/v1/favourites_controller_spec.rb b/spec/controllers/api/v1/favourites_controller_spec.rb index 46cf70f4d2..2bdf927f21 100644 --- a/spec/controllers/api/v1/favourites_controller_spec.rb +++ b/spec/controllers/api/v1/favourites_controller_spec.rb @@ -45,7 +45,7 @@ RSpec.describe Api::V1::FavouritesController, type: :controller do context 'with read scope and valid resource owner' do before do allow(controller).to receive(:doorkeeper_token) do - Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') + Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:favourites') end end diff --git a/spec/controllers/api/v1/filter_controller_spec.rb b/spec/controllers/api/v1/filter_controller_spec.rb index 3ffd8f784a..5948809e3f 100644 --- a/spec/controllers/api/v1/filter_controller_spec.rb +++ b/spec/controllers/api/v1/filter_controller_spec.rb @@ -4,13 +4,14 @@ RSpec.describe Api::V1::FiltersController, type: :controller do render_views let(:user) { Fabricate(:user) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read write') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } before do allow(controller).to receive(:doorkeeper_token) { token } end describe 'GET #index' do + let(:scopes) { 'read:filters' } let!(:filter) { Fabricate(:custom_filter, account: user.account) } it 'returns http success' do @@ -20,6 +21,8 @@ RSpec.describe Api::V1::FiltersController, type: :controller do end describe 'POST #create' do + let(:scopes) { 'write:filters' } + before do post :create, params: { phrase: 'magic', context: %w(home), irreversible: true } end @@ -39,6 +42,7 @@ RSpec.describe Api::V1::FiltersController, type: :controller do end describe 'GET #show' do + let(:scopes) { 'read:filters' } let(:filter) { Fabricate(:custom_filter, account: user.account) } it 'returns http success' do @@ -48,6 +52,7 @@ RSpec.describe Api::V1::FiltersController, type: :controller do end describe 'PUT #update' do + let(:scopes) { 'write:filters' } let(:filter) { Fabricate(:custom_filter, account: user.account) } before do @@ -64,6 +69,7 @@ RSpec.describe Api::V1::FiltersController, type: :controller do end describe 'DELETE #destroy' do + let(:scopes) { 'write:filters' } let(:filter) { Fabricate(:custom_filter, account: user.account) } before do diff --git a/spec/controllers/api/v1/follow_requests_controller_spec.rb b/spec/controllers/api/v1/follow_requests_controller_spec.rb index 3c0b84af8b..87292d9ce1 100644 --- a/spec/controllers/api/v1/follow_requests_controller_spec.rb +++ b/spec/controllers/api/v1/follow_requests_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::FollowRequestsController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice', locked: true)) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } let(:follower) { Fabricate(:account, username: 'bob') } before do @@ -13,6 +13,8 @@ RSpec.describe Api::V1::FollowRequestsController, type: :controller do end describe 'GET #index' do + let(:scopes) { 'read:follows' } + before do get :index, params: { limit: 1 } end @@ -23,6 +25,8 @@ RSpec.describe Api::V1::FollowRequestsController, type: :controller do end describe 'POST #authorize' do + let(:scopes) { 'write:follows' } + before do post :authorize, params: { id: follower.id } end @@ -37,6 +41,8 @@ RSpec.describe Api::V1::FollowRequestsController, type: :controller do end describe 'POST #reject' do + let(:scopes) { 'write:follows' } + before do post :reject, params: { id: follower.id } end diff --git a/spec/controllers/api/v1/follows_controller_spec.rb b/spec/controllers/api/v1/follows_controller_spec.rb index 38badb80ae..089e0fe5ec 100644 --- a/spec/controllers/api/v1/follows_controller_spec.rb +++ b/spec/controllers/api/v1/follows_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::FollowsController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:follows') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/lists/accounts_controller_spec.rb b/spec/controllers/api/v1/lists/accounts_controller_spec.rb index c37a481d6d..08c22de568 100644 --- a/spec/controllers/api/v1/lists/accounts_controller_spec.rb +++ b/spec/controllers/api/v1/lists/accounts_controller_spec.rb @@ -4,7 +4,7 @@ describe Api::V1::Lists::AccountsController do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read write') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } let(:list) { Fabricate(:list, account: user.account) } before do @@ -14,6 +14,8 @@ describe Api::V1::Lists::AccountsController do end describe 'GET #index' do + let(:scopes) { 'read:lists' } + it 'returns http success' do get :show, params: { list_id: list.id } @@ -22,6 +24,7 @@ describe Api::V1::Lists::AccountsController do end describe 'POST #create' do + let(:scopes) { 'write:lists' } let(:bob) { Fabricate(:account, username: 'bob') } before do @@ -39,6 +42,8 @@ describe Api::V1::Lists::AccountsController do end describe 'DELETE #destroy' do + let(:scopes) { 'write:lists' } + before do delete :destroy, params: { list_id: list.id, account_ids: [list.accounts.first.id] } end diff --git a/spec/controllers/api/v1/lists_controller_spec.rb b/spec/controllers/api/v1/lists_controller_spec.rb index 2134295815..e92213789a 100644 --- a/spec/controllers/api/v1/lists_controller_spec.rb +++ b/spec/controllers/api/v1/lists_controller_spec.rb @@ -4,12 +4,14 @@ RSpec.describe Api::V1::ListsController, type: :controller do render_views let!(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let!(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read write') } + let!(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } let!(:list) { Fabricate(:list, account: user.account) } before { allow(controller).to receive(:doorkeeper_token) { token } } describe 'GET #index' do + let(:scopes) { 'read:lists' } + it 'returns http success' do get :index expect(response).to have_http_status(200) @@ -17,6 +19,8 @@ RSpec.describe Api::V1::ListsController, type: :controller do end describe 'GET #show' do + let(:scopes) { 'read:lists' } + it 'returns http success' do get :show, params: { id: list.id } expect(response).to have_http_status(200) @@ -24,6 +28,8 @@ RSpec.describe Api::V1::ListsController, type: :controller do end describe 'POST #create' do + let(:scopes) { 'write:lists' } + before do post :create, params: { title: 'Foo bar' } end @@ -39,6 +45,8 @@ RSpec.describe Api::V1::ListsController, type: :controller do end describe 'PUT #update' do + let(:scopes) { 'write:lists' } + before do put :update, params: { id: list.id, title: 'Updated title' } end @@ -53,6 +61,8 @@ RSpec.describe Api::V1::ListsController, type: :controller do end describe 'DELETE #destroy' do + let(:scopes) { 'write:lists' } + before do delete :destroy, params: { id: list.id } end diff --git a/spec/controllers/api/v1/media_controller_spec.rb b/spec/controllers/api/v1/media_controller_spec.rb index ce260eb90a..f01fcd9424 100644 --- a/spec/controllers/api/v1/media_controller_spec.rb +++ b/spec/controllers/api/v1/media_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::MediaController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:media') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/mutes_controller_spec.rb b/spec/controllers/api/v1/mutes_controller_spec.rb index dc4a9753a0..f9603b7ff1 100644 --- a/spec/controllers/api/v1/mutes_controller_spec.rb +++ b/spec/controllers/api/v1/mutes_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::MutesController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'follow') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:mutes') } before do Fabricate(:mute, account: user.account, hide_notifications: false) diff --git a/spec/controllers/api/v1/notifications_controller_spec.rb b/spec/controllers/api/v1/notifications_controller_spec.rb index 2e6163fcd6..9f679cb8a7 100644 --- a/spec/controllers/api/v1/notifications_controller_spec.rb +++ b/spec/controllers/api/v1/notifications_controller_spec.rb @@ -4,7 +4,7 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } let(:other) { Fabricate(:user, account: Fabricate(:account, username: 'bob')) } before do @@ -12,6 +12,8 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do end describe 'GET #show' do + let(:scopes) { 'read:notifications' } + it 'returns http success' do notification = Fabricate(:notification, account: user.account) get :show, params: { id: notification.id } @@ -21,6 +23,8 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do end describe 'POST #dismiss' do + let(:scopes) { 'write:notifications' } + it 'destroys the notification' do notification = Fabricate(:notification, account: user.account) post :dismiss, params: { id: notification.id } @@ -31,6 +35,8 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do end describe 'POST #clear' do + let(:scopes) { 'write:notifications' } + it 'clears notifications for the account' do notification = Fabricate(:notification, account: user.account) post :clear @@ -41,6 +47,8 @@ RSpec.describe Api::V1::NotificationsController, type: :controller do end describe 'GET #index' do + let(:scopes) { 'read:notifications' } + before do first_status = PostStatusService.new.call(user.account, 'Test') @reblog_of_first_status = ReblogService.new.call(other.account, first_status) diff --git a/spec/controllers/api/v1/reports_controller_spec.rb b/spec/controllers/api/v1/reports_controller_spec.rb index 1e1ef9308b..ac93998c69 100644 --- a/spec/controllers/api/v1/reports_controller_spec.rb +++ b/spec/controllers/api/v1/reports_controller_spec.rb @@ -6,13 +6,15 @@ RSpec.describe Api::V1::ReportsController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read write') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: scopes) } before do allow(controller).to receive(:doorkeeper_token) { token } end describe 'GET #index' do + let(:scopes) { 'read:reports' } + it 'returns http success' do get :index @@ -21,6 +23,7 @@ RSpec.describe Api::V1::ReportsController, type: :controller do end describe 'POST #create' do + let(:scopes) { 'write:reports' } let!(:status) { Fabricate(:status) } let!(:admin) { Fabricate(:user, admin: true) } diff --git a/spec/controllers/api/v1/search_controller_spec.rb b/spec/controllers/api/v1/search_controller_spec.rb index 0247038675..c9e544cc79 100644 --- a/spec/controllers/api/v1/search_controller_spec.rb +++ b/spec/controllers/api/v1/search_controller_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Api::V1::SearchController, type: :controller do render_views let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:search') } before do allow(controller).to receive(:doorkeeper_token) { token } diff --git a/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb b/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb index c873e05dd8..23b5d7de92 100644 --- a/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/favourited_by_accounts_controller_spec.rb @@ -5,7 +5,7 @@ RSpec.describe Api::V1::Statuses::FavouritedByAccountsController, type: :control let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'read:accounts') } context 'with an oauth token' do before do diff --git a/spec/controllers/api/v1/statuses/favourites_controller_spec.rb b/spec/controllers/api/v1/statuses/favourites_controller_spec.rb index 53f602616d..24a760e20e 100644 --- a/spec/controllers/api/v1/statuses/favourites_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/favourites_controller_spec.rb @@ -7,7 +7,7 @@ describe Api::V1::Statuses::FavouritesController do let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write', application: app) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:favourites', application: app) } context 'with an oauth token' do before do diff --git a/spec/controllers/api/v1/statuses/mutes_controller_spec.rb b/spec/controllers/api/v1/statuses/mutes_controller_spec.rb index 13b4625d19..966398580d 100644 --- a/spec/controllers/api/v1/statuses/mutes_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/mutes_controller_spec.rb @@ -7,7 +7,7 @@ describe Api::V1::Statuses::MutesController do let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write', application: app) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:mutes', application: app) } context 'with an oauth token' do before do diff --git a/spec/controllers/api/v1/statuses/pins_controller_spec.rb b/spec/controllers/api/v1/statuses/pins_controller_spec.rb index 8f5b0800b0..13405d285d 100644 --- a/spec/controllers/api/v1/statuses/pins_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/pins_controller_spec.rb @@ -7,7 +7,7 @@ describe Api::V1::Statuses::PinsController do let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write', application: app) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:accounts', application: app) } context 'with an oauth token' do before do diff --git a/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb b/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb index 9c0c2b60cb..d758786dc9 100644 --- a/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/reblogged_by_accounts_controller_spec.rb @@ -5,7 +5,7 @@ RSpec.describe Api::V1::Statuses::RebloggedByAccountsController, type: :controll let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'read:accounts') } context 'with an oauth token' do before do diff --git a/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb b/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb index e60f8da2a4..d14ca3e8b6 100644 --- a/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb +++ b/spec/controllers/api/v1/statuses/reblogs_controller_spec.rb @@ -7,7 +7,7 @@ describe Api::V1::Statuses::ReblogsController do let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write', application: app) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'write:statuses', application: app) } context 'with an oauth token' do before do diff --git a/spec/controllers/api/v1/statuses_controller_spec.rb b/spec/controllers/api/v1/statuses_controller_spec.rb index 27e4f4eb24..8bc3b0c671 100644 --- a/spec/controllers/api/v1/statuses_controller_spec.rb +++ b/spec/controllers/api/v1/statuses_controller_spec.rb @@ -5,7 +5,7 @@ RSpec.describe Api::V1::StatusesController, type: :controller do let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } let(:app) { Fabricate(:application, name: 'Test app', website: 'http://testapp.com') } - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: 'write') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, application: app, scopes: scopes) } context 'with an oauth token' do before do @@ -13,6 +13,7 @@ RSpec.describe Api::V1::StatusesController, type: :controller do end describe 'GET #show' do + let(:scopes) { 'read:statuses' } let(:status) { Fabricate(:status, account: user.account) } it 'returns http success' do @@ -22,6 +23,7 @@ RSpec.describe Api::V1::StatusesController, type: :controller do end describe 'GET #context' do + let(:scopes) { 'read:statuses' } let(:status) { Fabricate(:status, account: user.account) } before do @@ -35,6 +37,8 @@ RSpec.describe Api::V1::StatusesController, type: :controller do end describe 'POST #create' do + let(:scopes) { 'write:statuses' } + before do post :create, params: { status: 'Hello world' } end @@ -45,6 +49,7 @@ RSpec.describe Api::V1::StatusesController, type: :controller do end describe 'DELETE #destroy' do + let(:scopes) { 'write:statuses' } let(:status) { Fabricate(:status, account: user.account) } before do diff --git a/spec/controllers/api/v1/timelines/home_controller_spec.rb b/spec/controllers/api/v1/timelines/home_controller_spec.rb index 85b0316418..a667c33fad 100644 --- a/spec/controllers/api/v1/timelines/home_controller_spec.rb +++ b/spec/controllers/api/v1/timelines/home_controller_spec.rb @@ -12,7 +12,7 @@ describe Api::V1::Timelines::HomeController do end context 'with a user context' do - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:statuses') } describe 'GET #show' do before do diff --git a/spec/controllers/api/v1/timelines/list_controller_spec.rb b/spec/controllers/api/v1/timelines/list_controller_spec.rb index 1729217c91..93a2be6e6c 100644 --- a/spec/controllers/api/v1/timelines/list_controller_spec.rb +++ b/spec/controllers/api/v1/timelines/list_controller_spec.rb @@ -13,7 +13,7 @@ describe Api::V1::Timelines::ListController do end context 'with a user context' do - let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read') } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:lists') } describe 'GET #show' do before do diff --git a/spec/controllers/api/v2/search_controller_spec.rb b/spec/controllers/api/v2/search_controller_spec.rb new file mode 100644 index 0000000000..8ee8753ded --- /dev/null +++ b/spec/controllers/api/v2/search_controller_spec.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe Api::V2::SearchController, type: :controller do + render_views + + let(:user) { Fabricate(:user, account: Fabricate(:account, username: 'alice')) } + let(:token) { Fabricate(:accessible_access_token, resource_owner_id: user.id, scopes: 'read:search') } + + before do + allow(controller).to receive(:doorkeeper_token) { token } + end + + describe 'GET #index' do + it 'returns http success' do + get :index, params: { q: 'test' } + + expect(response).to have_http_status(200) + end + end +end