[#1234] Permissions-related fixes / new functionality (Masto 2.4.3 scopes).

This commit is contained in:
Ivan Tashkinov 2019-09-15 18:22:08 +03:00
parent b63faf9819
commit e6f43a831b
14 changed files with 374 additions and 197 deletions

View file

@ -6,6 +6,8 @@ defmodule Pleroma.Plugs.OAuthScopesPlug do
import Plug.Conn import Plug.Conn
import Pleroma.Web.Gettext import Pleroma.Web.Gettext
alias Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug
@behaviour Plug @behaviour Plug
def init(%{scopes: _} = options), do: options def init(%{scopes: _} = options), do: options
@ -17,7 +19,7 @@ def call(%Plug.Conn{assigns: assigns} = conn, %{scopes: scopes} = options) do
cond do cond do
is_nil(token) -> is_nil(token) ->
conn maybe_perform_instance_privacy_check(conn, options)
op == :| && Enum.any?(matched_scopes) -> op == :| && Enum.any?(matched_scopes) ->
conn conn
@ -29,6 +31,7 @@ def call(%Plug.Conn{assigns: assigns} = conn, %{scopes: scopes} = options) do
conn conn
|> assign(:user, nil) |> assign(:user, nil)
|> assign(:token, nil) |> assign(:token, nil)
|> maybe_perform_instance_privacy_check(options)
true -> true ->
missing_scopes = scopes -- matched_scopes missing_scopes = scopes -- matched_scopes
@ -56,4 +59,11 @@ def filter_descendants(scopes, supported_scopes) do
end end
) )
end end
defp maybe_perform_instance_privacy_check(%Plug.Conn{} = conn, options) do
case options[:skip_instance_privacy_check] do
true -> conn
_ -> EnsurePublicOrAuthenticatedPlug.call(conn, [])
end
end
end end

View file

@ -23,6 +23,11 @@ defmodule Pleroma.Web.ActivityPub.ActivityPubController do
action_fallback(:errors) action_fallback(:errors)
plug(
Pleroma.Plugs.OAuthScopesPlug,
%{scopes: ["read:accounts"]} when action in [:followers, :following]
)
plug(Pleroma.Web.FederatingPlug when action in [:inbox, :relay]) plug(Pleroma.Web.FederatingPlug when action in [:inbox, :relay])
plug(:set_requester_reachable when action in [:inbox]) plug(:set_requester_reachable when action in [:inbox])
plug(:relay_active? when action in [:relay]) plug(:relay_active? when action in [:relay])

View file

@ -6,6 +6,7 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
use Pleroma.Web, :controller use Pleroma.Web, :controller
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.ModerationLog alias Pleroma.ModerationLog
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.User alias Pleroma.User
alias Pleroma.UserInviteToken alias Pleroma.UserInviteToken
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
@ -23,6 +24,56 @@ defmodule Pleroma.Web.AdminAPI.AdminAPIController do
require Logger require Logger
plug(OAuthScopesPlug, %{scopes: ["read:statuses"]} when action == :list_user_statuses)
plug(
OAuthScopesPlug,
%{scopes: ["write:statuses"]} when action in [:status_update, :status_delete]
)
plug(
OAuthScopesPlug,
%{scopes: ["read"]}
when action in [
:list_reports,
:report_show,
:right_get,
:get_invite_token,
:invites,
:get_password_reset,
:list_users,
:user_show,
:config_show,
:migrate_to_db,
:migrate_from_db,
:list_log
]
)
plug(
OAuthScopesPlug,
%{scopes: ["write"]}
when action in [
:report_update_state,
:report_respond,
:user_follow,
:user_unfollow,
:user_delete,
:users_create,
:user_toggle_activation,
:tag_users,
:untag_users,
:right_add,
:right_delete,
:set_activation_status,
:relay_follow,
:relay_unfollow,
:revoke_invite,
:email_invite,
:config_update
]
)
@users_page_size 50 @users_page_size 50
action_fallback(:errors) action_fallback(:errors)

View file

@ -5,11 +5,20 @@
defmodule Pleroma.Web.MastodonAPI.ListController do defmodule Pleroma.Web.MastodonAPI.ListController do
use Pleroma.Web, :controller use Pleroma.Web, :controller
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.MastodonAPI.AccountView alias Pleroma.Web.MastodonAPI.AccountView
plug(:list_by_id_and_user when action not in [:index, :create]) plug(:list_by_id_and_user when action not in [:index, :create])
plug(OAuthScopesPlug, %{scopes: ["read:lists"]} when action in [:index, :show, :list_accounts])
plug(
OAuthScopesPlug,
%{scopes: ["write:lists"]}
when action in [:create, :update, :delete, :add_to_list, :remove_from_list]
)
action_fallback(Pleroma.Web.MastodonAPI.FallbackController) action_fallback(Pleroma.Web.MastodonAPI.FallbackController)
# GET /api/v1/lists # GET /api/v1/lists

View file

@ -53,6 +53,123 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
require Logger require Logger
require Pleroma.Constants require Pleroma.Constants
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug when action != :index)
@unauthenticated_access %{fallback: :proceed_unauthenticated, scopes: []}
plug(
OAuthScopesPlug,
%{scopes: ["read"], skip_instance_privacy_check: true} when action == :index
)
plug(
OAuthScopesPlug,
%{scopes: ["read"]} when action in [:suggestions, :verify_app_credentials]
)
plug(
OAuthScopesPlug,
%{scopes: ["write:accounts"]}
# Note: the following actions are not permission-secured in Mastodon:
when action in [
:put_settings,
:update_avatar,
:update_banner,
:update_background,
:set_mascot
]
)
plug(
OAuthScopesPlug,
%{scopes: ["write:accounts"]}
when action in [:pin_status, :unpin_status, :update_credentials]
)
plug(
OAuthScopesPlug,
%{scopes: ["read:statuses"]}
when action in [
:conversations,
:scheduled_statuses,
:show_scheduled_status,
:home_timeline,
:dm_timeline
]
)
plug(
OAuthScopesPlug,
%{@unauthenticated_access | scopes: ["read:statuses"]}
when action in [:user_statuses, :get_status, :get_context, :status_card, :get_poll]
)
plug(
OAuthScopesPlug,
%{scopes: ["write:statuses"]}
when action in [
:update_scheduled_status,
:delete_scheduled_status,
:post_status,
:delete_status,
:reblog_status,
:unreblog_status,
:poll_vote
]
)
plug(OAuthScopesPlug, %{scopes: ["write:conversations"]} when action == :conversation_read)
plug(
OAuthScopesPlug,
%{scopes: ["read:accounts"]}
when action in [:endorsements, :verify_credentials, :followers, :following, :get_mascot]
)
plug(
OAuthScopesPlug,
%{@unauthenticated_access | scopes: ["read:accounts"]}
when action in [:user, :favourited_by, :reblogged_by]
)
plug(
OAuthScopesPlug,
%{scopes: ["read:favourites"]} when action in [:favourites, :user_favourites]
)
plug(
OAuthScopesPlug,
%{scopes: ["write:favourites"]} when action in [:fav_status, :unfav_status]
)
plug(OAuthScopesPlug, %{scopes: ["read:filters"]} when action in [:get_filters, :get_filter])
plug(
OAuthScopesPlug,
%{scopes: ["write:filters"]} when action in [:create_filter, :update_filter, :delete_filter]
)
plug(OAuthScopesPlug, %{scopes: ["read:lists"]} when action in [:account_lists, :list_timeline])
plug(OAuthScopesPlug, %{scopes: ["write:media"]} when action in [:upload, :update_media])
plug(
OAuthScopesPlug,
%{scopes: ["read:notifications"]} when action in [:notifications, :get_notification]
)
plug(
OAuthScopesPlug,
%{scopes: ["write:notifications"]}
when action in [:clear_notifications, :dismiss_notification, :destroy_multiple_notifications]
)
plug(
OAuthScopesPlug,
%{scopes: ["write:reports"]}
when action in [:create_report, :report_update_state, :report_respond]
)
plug( plug(
OAuthScopesPlug, OAuthScopesPlug,
%{scopes: ["follow", "read:blocks"]} when action in [:blocks, :domain_blocks] %{scopes: ["follow", "read:blocks"]} when action in [:blocks, :domain_blocks]
@ -64,6 +181,7 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
when action in [:block, :unblock, :block_domain, :unblock_domain] when action in [:block, :unblock, :block_domain, :unblock_domain]
) )
plug(OAuthScopesPlug, %{scopes: ["read:follows"]} when action == :relationships)
plug(OAuthScopesPlug, %{scopes: ["follow", "read:follows"]} when action == :follow_requests) plug(OAuthScopesPlug, %{scopes: ["follow", "read:follows"]} when action == :follow_requests)
plug( plug(
@ -84,8 +202,15 @@ defmodule Pleroma.Web.MastodonAPI.MastodonAPIController do
plug( plug(
OAuthScopesPlug, OAuthScopesPlug,
%{scopes: ["write:mutes"]} %{scopes: ["write:mutes"]} when action in [:mute_conversation, :unmute_conversation]
when action in [:mute_conversation, :unmute_conversation] )
# Note: scopes not present in Mastodon: read:bookmarks, write:bookmarks
plug(OAuthScopesPlug, %{scopes: ["read:bookmarks"]} when action == :bookmarks)
plug(
OAuthScopesPlug,
%{scopes: ["write:bookmarks"]} when action in [:bookmark_status, :unbookmark_status]
) )
@rate_limited_relations_actions ~w(follow unfollow)a @rate_limited_relations_actions ~w(follow unfollow)a
@ -776,7 +901,7 @@ def dismiss_notification(%{assigns: %{user: user}} = conn, %{"id" => id} = _para
end end
end end
def destroy_multiple(%{assigns: %{user: user}} = conn, %{"ids" => ids} = _params) do def destroy_multiple_notifications(%{assigns: %{user: user}} = conn, %{"ids" => ids} = _params) do
Notification.destroy_multiple(user, ids) Notification.destroy_multiple(user, ids)
json(conn, %{}) json(conn, %{})
end end
@ -1488,6 +1613,8 @@ def empty_object(conn, _) do
json(conn, %{}) json(conn, %{})
end end
def endorsements(conn, params), do: empty_array(conn, params)
def get_filters(%{assigns: %{user: user}} = conn, _) do def get_filters(%{assigns: %{user: user}} = conn, _) do
filters = Filter.get_filters(user) filters = Filter.get_filters(user)
res = FilterView.render("filters.json", filters: filters) res = FilterView.render("filters.json", filters: filters)
@ -1610,7 +1737,7 @@ def status_card(%{assigns: %{user: user}} = conn, %{"id" => status_id}) do
end end
end end
def reports(%{assigns: %{user: user}} = conn, params) do def create_report(%{assigns: %{user: user}} = conn, params) do
case CommonAPI.report(user, params) do case CommonAPI.report(user, params) do
{:ok, activity} -> {:ok, activity} ->
conn conn

View file

@ -6,6 +6,7 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
use Pleroma.Web, :controller use Pleroma.Web, :controller
alias Pleroma.Activity alias Pleroma.Activity
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Plugs.RateLimiter alias Pleroma.Plugs.RateLimiter
alias Pleroma.Repo alias Pleroma.Repo
alias Pleroma.User alias Pleroma.User
@ -15,6 +16,10 @@ defmodule Pleroma.Web.MastodonAPI.SearchController do
alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MastodonAPI.StatusView
require Logger require Logger
# Note: Mastodon doesn't allow unauthenticated access (requires read:accounts / read:search)
plug(OAuthScopesPlug, %{scopes: ["read:search"], fallback: :proceed_unauthenticated})
plug(RateLimiter, :search when action in [:search, :search2, :account_search]) plug(RateLimiter, :search when action in [:search, :search2, :account_search])
def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do def account_search(%{assigns: %{user: user}} = conn, %{"q" => query} = params) do

View file

@ -12,6 +12,8 @@ defmodule Pleroma.Web.MastodonAPI.SubscriptionController do
action_fallback(:errors) action_fallback(:errors)
plug(Pleroma.Plugs.OAuthScopesPlug, %{scopes: ["push"]})
# Creates PushSubscription # Creates PushSubscription
# POST /api/v1/push/subscription # POST /api/v1/push/subscription
# #

View file

@ -9,11 +9,24 @@ defmodule Pleroma.Web.PleromaAPI.PleromaAPIController do
alias Pleroma.Conversation.Participation alias Pleroma.Conversation.Participation
alias Pleroma.Notification alias Pleroma.Notification
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.Web.ActivityPub.ActivityPub alias Pleroma.Web.ActivityPub.ActivityPub
alias Pleroma.Web.MastodonAPI.ConversationView alias Pleroma.Web.MastodonAPI.ConversationView
alias Pleroma.Web.MastodonAPI.NotificationView alias Pleroma.Web.MastodonAPI.NotificationView
alias Pleroma.Web.MastodonAPI.StatusView alias Pleroma.Web.MastodonAPI.StatusView
plug(
OAuthScopesPlug,
%{scopes: ["read:statuses"]} when action in [:conversation, :conversation_statuses]
)
plug(
OAuthScopesPlug,
%{scopes: ["write:conversations"]} when action in [:conversations, :conversation_read]
)
plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :read_notification)
def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do def conversation(%{assigns: %{user: user}} = conn, %{"id" => participation_id}) do
with %Participation{} = participation <- Participation.get(participation_id), with %Participation{} = participation <- Participation.get(participation_id),
true <- user.id == participation.user_id do true <- user.id == participation.user_id do

View file

@ -87,27 +87,6 @@ defmodule Pleroma.Web.Router do
plug(Pleroma.Plugs.EnsureUserKeyPlug) plug(Pleroma.Plugs.EnsureUserKeyPlug)
end end
pipeline :oauth_read_or_public do
plug(Pleroma.Plugs.OAuthScopesPlug, %{
scopes: ["read"],
fallback: :proceed_unauthenticated
})
plug(Pleroma.Plugs.EnsurePublicOrAuthenticatedPlug)
end
pipeline :oauth_read do
plug(Pleroma.Plugs.OAuthScopesPlug, %{scopes: ["read"]})
end
pipeline :oauth_write do
plug(Pleroma.Plugs.OAuthScopesPlug, %{scopes: ["write"]})
end
pipeline :oauth_push do
plug(Pleroma.Plugs.OAuthScopesPlug, %{scopes: ["push"]})
end
pipeline :well_known do pipeline :well_known do
plug(:accepts, ["json", "jrd+json", "xml", "xrd+xml"]) plug(:accepts, ["json", "jrd+json", "xml", "xrd+xml"])
end end
@ -149,7 +128,12 @@ defmodule Pleroma.Web.Router do
end end
scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do scope "/api/pleroma/admin", Pleroma.Web.AdminAPI do
pipe_through([:admin_api, :oauth_write]) pipe_through(:admin_api)
get("/reports", AdminAPIController, :list_reports)
get("/reports/:id", AdminAPIController, :report_show)
put("/reports/:id", AdminAPIController, :report_update_state)
post("/reports/:id/respond", AdminAPIController, :report_respond)
post("/users/follow", AdminAPIController, :user_follow) post("/users/follow", AdminAPIController, :user_follow)
post("/users/unfollow", AdminAPIController, :user_unfollow) post("/users/unfollow", AdminAPIController, :user_unfollow)
@ -184,15 +168,6 @@ defmodule Pleroma.Web.Router do
get("/users", AdminAPIController, :list_users) get("/users", AdminAPIController, :list_users)
get("/users/:nickname", AdminAPIController, :user_show) get("/users/:nickname", AdminAPIController, :user_show)
get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses)
get("/reports", AdminAPIController, :list_reports)
get("/reports/:id", AdminAPIController, :report_show)
put("/reports/:id", AdminAPIController, :report_update_state)
post("/reports/:id/respond", AdminAPIController, :report_respond)
put("/statuses/:id", AdminAPIController, :status_update)
delete("/statuses/:id", AdminAPIController, :status_delete)
get("/config", AdminAPIController, :config_show) get("/config", AdminAPIController, :config_show)
post("/config", AdminAPIController, :config_update) post("/config", AdminAPIController, :config_update)
@ -200,6 +175,10 @@ defmodule Pleroma.Web.Router do
get("/config/migrate_from_db", AdminAPIController, :migrate_from_db) get("/config/migrate_from_db", AdminAPIController, :migrate_from_db)
get("/moderation_log", AdminAPIController, :list_log) get("/moderation_log", AdminAPIController, :list_log)
get("/users/:nickname/statuses", AdminAPIController, :list_user_statuses)
put("/statuses/:id", AdminAPIController, :status_update)
delete("/statuses/:id", AdminAPIController, :status_delete)
end end
scope "/", Pleroma.Web.TwitterAPI do scope "/", Pleroma.Web.TwitterAPI do
@ -213,19 +192,13 @@ defmodule Pleroma.Web.Router do
scope "/api/pleroma", Pleroma.Web.TwitterAPI do scope "/api/pleroma", Pleroma.Web.TwitterAPI do
pipe_through(:authenticated_api) pipe_through(:authenticated_api)
scope [] do post("/change_password", UtilController, :change_password)
pipe_through(:oauth_write) post("/delete_account", UtilController, :delete_account)
put("/notification_settings", UtilController, :update_notificaton_settings)
post("/disable_account", UtilController, :disable_account)
post("/change_password", UtilController, :change_password) post("/blocks_import", UtilController, :blocks_import)
post("/delete_account", UtilController, :delete_account) post("/follow_import", UtilController, :follow_import)
put("/notification_settings", UtilController, :update_notificaton_settings)
post("/disable_account", UtilController, :disable_account)
end
scope [] do
post("/blocks_import", UtilController, :blocks_import)
post("/follow_import", UtilController, :follow_import)
end
end end
scope "/oauth", Pleroma.Web.OAuth do scope "/oauth", Pleroma.Web.OAuth do
@ -252,148 +225,134 @@ defmodule Pleroma.Web.Router do
scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do scope "/api/v1/pleroma", Pleroma.Web.PleromaAPI do
pipe_through(:authenticated_api) pipe_through(:authenticated_api)
scope [] do get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses)
pipe_through(:oauth_read) get("/conversations/:id", PleromaAPIController, :conversation)
get("/conversations/:id/statuses", PleromaAPIController, :conversation_statuses) patch("/conversations/:id", PleromaAPIController, :update_conversation)
get("/conversations/:id", PleromaAPIController, :conversation) post("/notifications/read", PleromaAPIController, :read_notification)
end
scope [] do
pipe_through(:oauth_write)
patch("/conversations/:id", PleromaAPIController, :update_conversation)
post("/notifications/read", PleromaAPIController, :read_notification)
end
end end
scope "/api/v1", Pleroma.Web.MastodonAPI do scope "/api/v1", Pleroma.Web.MastodonAPI do
pipe_through(:authenticated_api) pipe_through(:authenticated_api)
scope [] do get("/blocks", MastodonAPIController, :blocks)
pipe_through(:oauth_read) get("/mutes", MastodonAPIController, :mutes)
get("/domain_blocks", MastodonAPIController, :domain_blocks)
get("/accounts/verify_credentials", MastodonAPIController, :verify_credentials) get("/accounts/:id/lists", MastodonAPIController, :account_lists)
get("/lists", ListController, :index)
get("/lists/:id", ListController, :show)
get("/lists/:id/accounts", ListController, :list_accounts)
get("/accounts/relationships", MastodonAPIController, :relationships) post("/notifications/clear", MastodonAPIController, :clear_notifications)
post("/notifications/dismiss", MastodonAPIController, :dismiss_notification)
get("/notifications", MastodonAPIController, :notifications)
get("/notifications/:id", MastodonAPIController, :get_notification)
get("/accounts/:id/lists", MastodonAPIController, :account_lists) delete(
get("/accounts/:id/identity_proofs", MastodonAPIController, :empty_array) "/notifications/destroy_multiple",
MastodonAPIController,
:destroy_multiple_notifications
)
get("/follow_requests", MastodonAPIController, :follow_requests) # Note: not present in Mastodon
get("/blocks", MastodonAPIController, :blocks) get("/bookmarks", MastodonAPIController, :bookmarks)
get("/mutes", MastodonAPIController, :mutes)
get("/timelines/home", MastodonAPIController, :home_timeline) get("/accounts/:id/identity_proofs", MastodonAPIController, :empty_array)
get("/timelines/direct", MastodonAPIController, :dm_timeline)
get("/favourites", MastodonAPIController, :favourites) get("/favourites", MastodonAPIController, :favourites)
get("/bookmarks", MastodonAPIController, :bookmarks)
post("/notifications/clear", MastodonAPIController, :clear_notifications) get("/accounts/relationships", MastodonAPIController, :relationships)
post("/notifications/dismiss", MastodonAPIController, :dismiss_notification)
get("/notifications", MastodonAPIController, :notifications)
get("/notifications/:id", MastodonAPIController, :get_notification)
delete("/notifications/destroy_multiple", MastodonAPIController, :destroy_multiple)
get("/scheduled_statuses", MastodonAPIController, :scheduled_statuses) get("/accounts/verify_credentials", MastodonAPIController, :verify_credentials)
get("/scheduled_statuses/:id", MastodonAPIController, :show_scheduled_status)
get("/lists", ListController, :index) get("/timelines/home", MastodonAPIController, :home_timeline)
get("/lists/:id", ListController, :show) get("/timelines/direct", MastodonAPIController, :dm_timeline)
get("/lists/:id/accounts", ListController, :list_accounts)
get("/domain_blocks", MastodonAPIController, :domain_blocks) get("/suggestions", MastodonAPIController, :suggestions)
get("/scheduled_statuses", MastodonAPIController, :scheduled_statuses)
get("/scheduled_statuses/:id", MastodonAPIController, :show_scheduled_status)
get("/follow_requests", MastodonAPIController, :follow_requests)
get("/filters", MastodonAPIController, :get_filters)
get("/endorsements", MastodonAPIController, :endorsements)
get("/conversations", MastodonAPIController, :conversations)
post("/conversations/:id/read", MastodonAPIController, :conversation_read)
get("/filters", MastodonAPIController, :get_filters) delete("/lists/:id", ListController, :delete)
post("/lists", ListController, :create)
put("/lists/:id", ListController, :update)
get("/suggestions", MastodonAPIController, :suggestions) post("/lists/:id/accounts", ListController, :add_to_list)
delete("/lists/:id/accounts", ListController, :remove_from_list)
get("/conversations", MastodonAPIController, :conversations) post("/reports", MastodonAPIController, :create_report)
post("/conversations/:id/read", MastodonAPIController, :conversation_read)
get("/endorsements", MastodonAPIController, :empty_array) patch("/pleroma/accounts/update_avatar", MastodonAPIController, :update_avatar)
end patch("/pleroma/accounts/update_banner", MastodonAPIController, :update_banner)
patch("/pleroma/accounts/update_background", MastodonAPIController, :update_background)
scope [] do get("/pleroma/mascot", MastodonAPIController, :get_mascot)
pipe_through(:oauth_write) put("/pleroma/mascot", MastodonAPIController, :set_mascot)
patch("/accounts/update_credentials", MastodonAPIController, :update_credentials) post("/media", MastodonAPIController, :upload)
put("/media/:id", MastodonAPIController, :update_media)
post("/statuses", MastodonAPIController, :post_status) patch("/accounts/update_credentials", MastodonAPIController, :update_credentials)
delete("/statuses/:id", MastodonAPIController, :delete_status)
post("/statuses/:id/reblog", MastodonAPIController, :reblog_status) post("/polls/:id/votes", MastodonAPIController, :poll_vote)
post("/statuses/:id/unreblog", MastodonAPIController, :unreblog_status)
post("/statuses/:id/favourite", MastodonAPIController, :fav_status)
post("/statuses/:id/unfavourite", MastodonAPIController, :unfav_status)
post("/statuses/:id/pin", MastodonAPIController, :pin_status)
post("/statuses/:id/unpin", MastodonAPIController, :unpin_status)
post("/statuses/:id/bookmark", MastodonAPIController, :bookmark_status)
post("/statuses/:id/unbookmark", MastodonAPIController, :unbookmark_status)
post("/statuses/:id/mute", MastodonAPIController, :mute_conversation)
post("/statuses/:id/unmute", MastodonAPIController, :unmute_conversation)
put("/scheduled_statuses/:id", MastodonAPIController, :update_scheduled_status) post("/statuses/:id/reblog", MastodonAPIController, :reblog_status)
delete("/scheduled_statuses/:id", MastodonAPIController, :delete_scheduled_status) post("/statuses/:id/unreblog", MastodonAPIController, :unreblog_status)
post("/polls/:id/votes", MastodonAPIController, :poll_vote) post("/statuses/:id/pin", MastodonAPIController, :pin_status)
post("/statuses/:id/unpin", MastodonAPIController, :unpin_status)
post("/media", MastodonAPIController, :upload) post("/statuses/:id/mute", MastodonAPIController, :mute_conversation)
put("/media/:id", MastodonAPIController, :update_media) post("/statuses/:id/unmute", MastodonAPIController, :unmute_conversation)
delete("/lists/:id", ListController, :delete) post("/statuses/:id/favourite", MastodonAPIController, :fav_status)
post("/lists", ListController, :create) post("/statuses/:id/unfavourite", MastodonAPIController, :unfav_status)
put("/lists/:id", ListController, :update)
post("/lists/:id/accounts", ListController, :add_to_list) post("/statuses", MastodonAPIController, :post_status)
delete("/lists/:id/accounts", ListController, :remove_from_list) delete("/statuses/:id", MastodonAPIController, :delete_status)
post("/filters", MastodonAPIController, :create_filter) put("/scheduled_statuses/:id", MastodonAPIController, :update_scheduled_status)
get("/filters/:id", MastodonAPIController, :get_filter) delete("/scheduled_statuses/:id", MastodonAPIController, :delete_scheduled_status)
put("/filters/:id", MastodonAPIController, :update_filter)
delete("/filters/:id", MastodonAPIController, :delete_filter)
patch("/pleroma/accounts/update_avatar", MastodonAPIController, :update_avatar) post("/filters", MastodonAPIController, :create_filter)
patch("/pleroma/accounts/update_banner", MastodonAPIController, :update_banner) get("/filters/:id", MastodonAPIController, :get_filter)
patch("/pleroma/accounts/update_background", MastodonAPIController, :update_background) put("/filters/:id", MastodonAPIController, :update_filter)
delete("/filters/:id", MastodonAPIController, :delete_filter)
get("/pleroma/mascot", MastodonAPIController, :get_mascot) post("/follows", MastodonAPIController, :follow)
put("/pleroma/mascot", MastodonAPIController, :set_mascot) post("/accounts/:id/follow", MastodonAPIController, :follow)
post("/reports", MastodonAPIController, :reports) post("/accounts/:id/unfollow", MastodonAPIController, :unfollow)
end post("/accounts/:id/block", MastodonAPIController, :block)
post("/accounts/:id/unblock", MastodonAPIController, :unblock)
post("/accounts/:id/mute", MastodonAPIController, :mute)
post("/accounts/:id/unmute", MastodonAPIController, :unmute)
scope [] do post("/follow_requests/:id/authorize", MastodonAPIController, :authorize_follow_request)
post("/follows", MastodonAPIController, :follow) post("/follow_requests/:id/reject", MastodonAPIController, :reject_follow_request)
post("/accounts/:id/follow", MastodonAPIController, :follow)
post("/accounts/:id/unfollow", MastodonAPIController, :unfollow) post("/domain_blocks", MastodonAPIController, :block_domain)
post("/accounts/:id/block", MastodonAPIController, :block) delete("/domain_blocks", MastodonAPIController, :unblock_domain)
post("/accounts/:id/unblock", MastodonAPIController, :unblock)
post("/accounts/:id/mute", MastodonAPIController, :mute)
post("/accounts/:id/unmute", MastodonAPIController, :unmute)
post("/follow_requests/:id/authorize", MastodonAPIController, :authorize_follow_request) post("/pleroma/accounts/:id/subscribe", MastodonAPIController, :subscribe)
post("/follow_requests/:id/reject", MastodonAPIController, :reject_follow_request) post("/pleroma/accounts/:id/unsubscribe", MastodonAPIController, :unsubscribe)
post("/domain_blocks", MastodonAPIController, :block_domain) post("/push/subscription", SubscriptionController, :create)
delete("/domain_blocks", MastodonAPIController, :unblock_domain) get("/push/subscription", SubscriptionController, :get)
put("/push/subscription", SubscriptionController, :update)
delete("/push/subscription", SubscriptionController, :delete)
post("/pleroma/accounts/:id/subscribe", MastodonAPIController, :subscribe) # Note: not present in Mastodon: bookmark, unbookmark
post("/pleroma/accounts/:id/unsubscribe", MastodonAPIController, :unsubscribe) post("/statuses/:id/bookmark", MastodonAPIController, :bookmark_status)
end post("/statuses/:id/unbookmark", MastodonAPIController, :unbookmark_status)
scope [] do
pipe_through(:oauth_push)
post("/push/subscription", SubscriptionController, :create)
get("/push/subscription", SubscriptionController, :get)
put("/push/subscription", SubscriptionController, :update)
delete("/push/subscription", SubscriptionController, :delete)
end
end end
scope "/api/web", Pleroma.Web.MastodonAPI do scope "/api/web", Pleroma.Web.MastodonAPI do
pipe_through([:authenticated_api, :oauth_write]) pipe_through(:authenticated_api)
put("/settings", MastodonAPIController, :put_settings) put("/settings", MastodonAPIController, :put_settings)
end end
@ -424,31 +383,29 @@ defmodule Pleroma.Web.Router do
:account_confirmation_resend :account_confirmation_resend
) )
scope [] do get("/timelines/public", MastodonAPIController, :public_timeline)
pipe_through(:oauth_read_or_public) get("/timelines/tag/:tag", MastodonAPIController, :hashtag_timeline)
get("/timelines/public", MastodonAPIController, :public_timeline) get("/pleroma/accounts/:id/favourites", MastodonAPIController, :user_favourites)
get("/timelines/tag/:tag", MastodonAPIController, :hashtag_timeline)
get("/timelines/list/:list_id", MastodonAPIController, :list_timeline)
get("/statuses/:id", MastodonAPIController, :get_status) get("/search", SearchController, :search)
get("/statuses/:id/context", MastodonAPIController, :get_context)
get("/polls/:id", MastodonAPIController, :get_poll) get("/polls/:id", MastodonAPIController, :get_poll)
get("/accounts/:id/statuses", MastodonAPIController, :user_statuses) get("/accounts/:id/followers", MastodonAPIController, :followers)
get("/accounts/:id/followers", MastodonAPIController, :followers) get("/accounts/:id/following", MastodonAPIController, :following)
get("/accounts/:id/following", MastodonAPIController, :following)
get("/accounts/:id", MastodonAPIController, :user)
get("/search", SearchController, :search) get("/timelines/list/:list_id", MastodonAPIController, :list_timeline)
get("/pleroma/accounts/:id/favourites", MastodonAPIController, :user_favourites) get("/accounts/:id", MastodonAPIController, :user)
end
get("/accounts/:id/statuses", MastodonAPIController, :user_statuses)
get("/statuses/:id", MastodonAPIController, :get_status)
get("/statuses/:id/context", MastodonAPIController, :get_context)
end end
scope "/api/v2", Pleroma.Web.MastodonAPI do scope "/api/v2", Pleroma.Web.MastodonAPI do
pipe_through([:api, :oauth_read_or_public]) pipe_through(:api)
get("/search", SearchController, :search2) get("/search", SearchController, :search2)
end end
@ -478,12 +435,7 @@ defmodule Pleroma.Web.Router do
get("/oauth_tokens", TwitterAPI.Controller, :oauth_tokens) get("/oauth_tokens", TwitterAPI.Controller, :oauth_tokens)
delete("/oauth_tokens/:id", TwitterAPI.Controller, :revoke_token) delete("/oauth_tokens/:id", TwitterAPI.Controller, :revoke_token)
post("/qvitter/statuses/notifications/read", TwitterAPI.Controller, :notifications_read)
scope [] do
pipe_through(:oauth_read)
post("/qvitter/statuses/notifications/read", TwitterAPI.Controller, :notifications_read)
end
end end
pipeline :ap_service_actor do pipeline :ap_service_actor do
@ -547,26 +499,16 @@ defmodule Pleroma.Web.Router do
scope "/", Pleroma.Web.ActivityPub do scope "/", Pleroma.Web.ActivityPub do
pipe_through([:activitypub_client]) pipe_through([:activitypub_client])
scope [] do get("/api/ap/whoami", ActivityPubController, :whoami)
pipe_through(:oauth_read) get("/users/:nickname/inbox", ActivityPubController, :read_inbox)
get("/api/ap/whoami", ActivityPubController, :whoami) post("/users/:nickname/outbox", ActivityPubController, :update_outbox)
get("/users/:nickname/inbox", ActivityPubController, :read_inbox) get("/users/:nickname/followers", ActivityPubController, :followers)
end get("/users/:nickname/following", ActivityPubController, :following)
scope [] do
pipe_through(:oauth_write)
post("/users/:nickname/outbox", ActivityPubController, :update_outbox)
end
scope [] do
pipe_through(:oauth_read_or_public)
get("/users/:nickname/followers", ActivityPubController, :followers)
get("/users/:nickname/following", ActivityPubController, :following)
end
end end
scope "/", Pleroma.Web.ActivityPub do scope "/", Pleroma.Web.ActivityPub do
pipe_through(:activitypub) pipe_through(:activitypub)
post("/inbox", ActivityPubController, :inbox) post("/inbox", ActivityPubController, :inbox)
post("/users/:nickname/inbox", ActivityPubController, :inbox) post("/users/:nickname/inbox", ActivityPubController, :inbox)
end end
@ -612,10 +554,7 @@ defmodule Pleroma.Web.Router do
post("/auth/password", MastodonAPIController, :password_reset) post("/auth/password", MastodonAPIController, :password_reset)
scope [] do get("/web/*path", MastodonAPIController, :index)
pipe_through(:oauth_read)
get("/web/*path", MastodonAPIController, :index)
end
end end
pipeline :remote_media do pipeline :remote_media do

View file

@ -27,6 +27,17 @@ defmodule Pleroma.Web.TwitterAPI.UtilController do
plug(OAuthScopesPlug, %{scopes: ["follow", "write:blocks"]} when action == :blocks_import) plug(OAuthScopesPlug, %{scopes: ["follow", "write:blocks"]} when action == :blocks_import)
plug(
OAuthScopesPlug,
%{scopes: ["write:accounts"]}
when action in [
:change_password,
:delete_account,
:update_notificaton_settings,
:disable_account
]
)
plug(Pleroma.Plugs.SetFormatPlug when action in [:config, :version]) plug(Pleroma.Plugs.SetFormatPlug when action in [:config, :version])
def help_test(conn, _params) do def help_test(conn, _params) do

View file

@ -7,12 +7,15 @@ defmodule Pleroma.Web.TwitterAPI.Controller do
alias Ecto.Changeset alias Ecto.Changeset
alias Pleroma.Notification alias Pleroma.Notification
alias Pleroma.Plugs.OAuthScopesPlug
alias Pleroma.User alias Pleroma.User
alias Pleroma.Web.OAuth.Token alias Pleroma.Web.OAuth.Token
alias Pleroma.Web.TwitterAPI.TokenView alias Pleroma.Web.TwitterAPI.TokenView
require Logger require Logger
plug(OAuthScopesPlug, %{scopes: ["write:notifications"]} when action == :notifications_read)
action_fallback(:errors) action_fallback(:errors)
def confirm_email(conn, %{"user_id" => uid, "token" => token}) do def confirm_email(conn, %{"user_id" => uid, "token" => token}) do

View file

@ -283,6 +283,7 @@ def oauth_token_factory do
%Pleroma.Web.OAuth.Token{ %Pleroma.Web.OAuth.Token{
token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(), token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(),
scopes: ["read"],
refresh_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(), refresh_token: :crypto.strong_rand_bytes(32) |> Base.url_encode64(),
user: build(:user), user: build(:user),
app_id: oauth_app.id, app_id: oauth_app.id,

View file

@ -257,7 +257,7 @@ test "updates the user's background", %{conn: conn} do
assert user_response["pleroma"]["background_image"] assert user_response["pleroma"]["background_image"]
end end
test "requires 'write' permission", %{conn: conn} do test "requires 'write:accounts' permission", %{conn: conn} do
token1 = insert(:oauth_token, scopes: ["read"]) token1 = insert(:oauth_token, scopes: ["read"])
token2 = insert(:oauth_token, scopes: ["write", "follow"]) token2 = insert(:oauth_token, scopes: ["write", "follow"])
@ -268,7 +268,8 @@ test "requires 'write' permission", %{conn: conn} do
|> patch("/api/v1/accounts/update_credentials", %{}) |> patch("/api/v1/accounts/update_credentials", %{})
if token == token1 do if token == token1 do
assert %{"error" => "Insufficient permissions: write."} == json_response(conn, 403) assert %{"error" => "Insufficient permissions: write:accounts."} ==
json_response(conn, 403)
else else
assert json_response(conn, 200) assert json_response(conn, 200)
end end

View file

@ -556,7 +556,7 @@ test "redirects with oauth authorization" do
"password" => "test", "password" => "test",
"client_id" => app.client_id, "client_id" => app.client_id,
"redirect_uri" => redirect_uri, "redirect_uri" => redirect_uri,
"scope" => "read write", "scope" => "read:subscope write",
"state" => "statepassed" "state" => "statepassed"
} }
}) })
@ -569,7 +569,7 @@ test "redirects with oauth authorization" do
assert %{"state" => "statepassed", "code" => code} = query assert %{"state" => "statepassed", "code" => code} = query
auth = Repo.get_by(Authorization, token: code) auth = Repo.get_by(Authorization, token: code)
assert auth assert auth
assert auth.scopes == ["read", "write"] assert auth.scopes == ["read:subscope", "write"]
end end
test "returns 401 for wrong credentials", %{conn: conn} do test "returns 401 for wrong credentials", %{conn: conn} do
@ -626,7 +626,7 @@ test "returns 401 for missing scopes", %{conn: conn} do
assert result =~ "This action is outside the authorized scopes" assert result =~ "This action is outside the authorized scopes"
end end
test "returns 401 for scopes beyond app scopes", %{conn: conn} do test "returns 401 for scopes beyond app scopes hierarchy", %{conn: conn} do
user = insert(:user) user = insert(:user)
app = insert(:oauth_app, scopes: ["read", "write"]) app = insert(:oauth_app, scopes: ["read", "write"])
redirect_uri = OAuthController.default_redirect_uri(app) redirect_uri = OAuthController.default_redirect_uri(app)