Merge pull request 'OAuth: support the profile scope' (#8012) from lambadalambda/pleroma:feature/oauth-profile-scope into develop
Reviewed-on: https://git.pleroma.social/pleroma/pleroma/pulls/8012
This commit is contained in:
commit
6963c22fcf
7 changed files with 90 additions and 4 deletions
1
changelog.d/oauth-profile-scope.add
Normal file
1
changelog.d/oauth-profile-scope.add
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Support the Mastodon `profile` OAuth scope, which only gives the public account from verify_credentials
|
||||||
|
|
@ -303,6 +303,10 @@ Additional fields are returned in the response:
|
||||||
- `id`: The primary key of this token in Pleroma's database.
|
- `id`: The primary key of this token in Pleroma's database.
|
||||||
- `me` (user tokens only): The ActivityPub ID of the user who owns the token.
|
- `me` (user tokens only): The ActivityPub ID of the user who owns the token.
|
||||||
|
|
||||||
|
### `profile` scope
|
||||||
|
|
||||||
|
As in Mastodon 4.3, a token with the `profile` scope can call `GET /api/v1/accounts/verify_credentials` and no other Mastodon API endpoint. Apps can use it to log users in with their fediverse account. Unless the token also has `read` or `read:accounts`, Pleroma returns only public data: unlike Mastodon, there is no `source.privacy`, no `follow_requests_count`, and none of the private `pleroma` fields such as `email`, `settings_store` and `chat_token`.
|
||||||
|
|
||||||
## Account Registration
|
## Account Registration
|
||||||
|
|
||||||
`POST /api/v1/accounts`
|
`POST /api/v1/accounts`
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ defmodule Pleroma.Web.ApiSpec.AccountOperation do
|
||||||
description: "Test to make sure that the user token works.",
|
description: "Test to make sure that the user token works.",
|
||||||
summary: "Verify account credentials",
|
summary: "Verify account credentials",
|
||||||
operationId: "AccountController.verify_credentials",
|
operationId: "AccountController.verify_credentials",
|
||||||
security: [%{"oAuth" => ["read:accounts"]}],
|
security: [%{"oAuth" => ["read:accounts"]}, %{"oAuth" => ["profile"]}],
|
||||||
responses: %{
|
responses: %{
|
||||||
200 => Operation.response("Account", "application/json", Account)
|
200 => Operation.response("Account", "application/json", Account)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
alias Pleroma.Web.MastodonAPI.MastodonAPI
|
||||||
alias Pleroma.Web.MastodonAPI.StatusView
|
alias Pleroma.Web.MastodonAPI.StatusView
|
||||||
alias Pleroma.Web.OAuth.OAuthController
|
alias Pleroma.Web.OAuth.OAuthController
|
||||||
|
alias Pleroma.Web.OAuth.Token
|
||||||
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
alias Pleroma.Web.Plugs.OAuthScopesPlug
|
||||||
alias Pleroma.Web.Plugs.RateLimiter
|
alias Pleroma.Web.Plugs.RateLimiter
|
||||||
alias Pleroma.Web.Registration
|
alias Pleroma.Web.Registration
|
||||||
|
|
@ -49,8 +50,12 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
OAuthScopesPlug,
|
OAuthScopesPlug,
|
||||||
%{scopes: ["read:accounts"]}
|
%{scopes: ["read:accounts", "profile"]} when action == :verify_credentials
|
||||||
when action in [:verify_credentials, :endorsements, :own_endorsements]
|
)
|
||||||
|
|
||||||
|
plug(
|
||||||
|
OAuthScopesPlug,
|
||||||
|
%{scopes: ["read:accounts"]} when action in [:endorsements, :own_endorsements]
|
||||||
)
|
)
|
||||||
|
|
||||||
plug(
|
plug(
|
||||||
|
|
@ -161,7 +166,18 @@ defmodule Pleroma.Web.MastodonAPI.AccountController do
|
||||||
end
|
end
|
||||||
|
|
||||||
@doc "GET /api/v1/accounts/verify_credentials"
|
@doc "GET /api/v1/accounts/verify_credentials"
|
||||||
def verify_credentials(%{assigns: %{user: user}} = conn, _) do
|
def verify_credentials(%{assigns: %{user: user, token: %Token{scopes: scopes}}} = conn, _) do
|
||||||
|
if OAuthScopesPlug.filter_descendants(["read:accounts"], scopes) == [] do
|
||||||
|
# The profile scope only identifies the user: show what anyone can see.
|
||||||
|
render(conn, "show.json", user: user, skip_visibility_check: true)
|
||||||
|
else
|
||||||
|
render_own_account(conn, user)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def verify_credentials(%{assigns: %{user: user}} = conn, _), do: render_own_account(conn, user)
|
||||||
|
|
||||||
|
defp render_own_account(conn, user) do
|
||||||
chat_token = Phoenix.Token.sign(conn, "user socket", user.id)
|
chat_token = Phoenix.Token.sign(conn, "user socket", user.id)
|
||||||
|
|
||||||
render(conn, "show.json",
|
render(conn, "show.json",
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,11 @@ msgstr "Write all using admin API"
|
||||||
msgid "follow"
|
msgid "follow"
|
||||||
msgstr "Read and write user relationships"
|
msgstr "Read and write user relationships"
|
||||||
|
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
#: lib/pleroma/web/api_spec/scopes/translator.ex:5
|
||||||
|
msgid "profile"
|
||||||
|
msgstr "Read only your public profile, to log in to other services"
|
||||||
|
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
#: lib/pleroma/web/api_spec/scopes/translator.ex:5
|
#: lib/pleroma/web/api_spec/scopes/translator.ex:5
|
||||||
msgid "push"
|
msgid "push"
|
||||||
|
|
|
||||||
|
|
@ -220,6 +220,11 @@ msgstr ""
|
||||||
msgid "read:mutes"
|
msgid "read:mutes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: lib/pleroma/web/api_spec/scopes/translator.ex:5
|
||||||
|
#, elixir-autogen, elixir-format
|
||||||
|
msgid "profile"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: lib/pleroma/web/api_spec/scopes/translator.ex:5
|
#: lib/pleroma/web/api_spec/scopes/translator.ex:5
|
||||||
#, elixir-autogen, elixir-format
|
#, elixir-autogen, elixir-format
|
||||||
msgid "push"
|
msgid "push"
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|
||||||
alias Pleroma.Web.ActivityPub.ActivityPub
|
alias Pleroma.Web.ActivityPub.ActivityPub
|
||||||
alias Pleroma.Web.ActivityPub.InternalFetchActor
|
alias Pleroma.Web.ActivityPub.InternalFetchActor
|
||||||
alias Pleroma.Web.CommonAPI
|
alias Pleroma.Web.CommonAPI
|
||||||
|
alias Pleroma.Web.MastodonAPI.AccountView
|
||||||
alias Pleroma.Web.OAuth.Token
|
alias Pleroma.Web.OAuth.Token
|
||||||
alias Pleroma.Web.Plugs.SetLocalePlug
|
alias Pleroma.Web.Plugs.SetLocalePlug
|
||||||
|
|
||||||
|
|
@ -2033,6 +2034,60 @@ defmodule Pleroma.Web.MastodonAPI.AccountControllerTest do
|
||||||
|
|
||||||
assert id == to_string(user.id)
|
assert id == to_string(user.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "the profile scope only gets the public account" do
|
||||||
|
user = insert(:user, default_scope: "private", pleroma_settings_store: %{"fe" => %{}})
|
||||||
|
%{conn: conn} = oauth_access(["profile"], user: user)
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/accounts/verify_credentials")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
assert response ==
|
||||||
|
AccountView.render("show.json", user: user, skip_visibility_check: true)
|
||||||
|
|> Jason.encode!()
|
||||||
|
|> Jason.decode!()
|
||||||
|
|
||||||
|
refute Map.has_key?(response["source"], "privacy")
|
||||||
|
refute Map.has_key?(response, "follow_requests_count")
|
||||||
|
|
||||||
|
for key <- ~w(email settings_store chat_token notification_settings
|
||||||
|
unread_notifications_count unread_conversation_count allow_following_move) do
|
||||||
|
refute Map.has_key?(response["pleroma"], key), "#{key} must not be shown"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
test "the profile scope with read:accounts gets the full account" do
|
||||||
|
%{conn: conn} = oauth_access(["profile", "read:accounts"])
|
||||||
|
|
||||||
|
response =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/accounts/verify_credentials")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
assert response["source"]["privacy"]
|
||||||
|
assert response["pleroma"]["chat_token"]
|
||||||
|
end
|
||||||
|
|
||||||
|
test "the profile scope works when unauthenticated users cannot see profiles" do
|
||||||
|
clear_config([:restrict_unauthenticated, :profiles, :local], true)
|
||||||
|
%{user: user, conn: conn} = oauth_access(["profile"])
|
||||||
|
|
||||||
|
assert %{"id" => id} =
|
||||||
|
conn
|
||||||
|
|> get("/api/v1/accounts/verify_credentials")
|
||||||
|
|> json_response_and_validate_schema(200)
|
||||||
|
|
||||||
|
assert id == to_string(user.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
test "the profile scope does not give access to other endpoints" do
|
||||||
|
%{conn: conn} = oauth_access(["profile"])
|
||||||
|
|
||||||
|
assert conn |> get("/api/v1/timelines/home") |> json_response(403)
|
||||||
|
assert conn |> get("/api/v1/follow_requests") |> json_response(403)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "user relationships" do
|
describe "user relationships" do
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue