Introduce application tokens

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2023-02-15 19:31:23 +01:00
parent 39768693c5
commit 2ee329ff7b
30 changed files with 1533 additions and 32 deletions

View File

@@ -0,0 +1,92 @@
defmodule Mobilizon.GraphQL.Resolvers.Application do
@moduledoc """
Handles the Application-related GraphQL calls.
"""
alias Mobilizon.Applications, as: ApplicationManager
alias Mobilizon.Applications.{Application, ApplicationToken}
alias Mobilizon.Service.Auth.Applications
alias Mobilizon.Users.User
import Mobilizon.Web.Gettext, only: [dgettext: 2]
require Logger
@doc """
Create an application
"""
@spec authorize(any(), map(), Absinthe.Resolution.t()) :: {:ok, map()} | {:error, String.t()}
def authorize(
_parent,
%{client_id: client_id, redirect_uri: redirect_uri, scope: scope, state: state},
%{context: %{current_user: %User{id: user_id}}}
) do
case Applications.autorize(client_id, redirect_uri, scope, user_id) do
{:ok, code} ->
{:ok, %{code: code, state: state}}
{:error, :application_not_found} ->
{:error,
dgettext(
"errors",
"No application with this client_id was found"
)}
{:error, :redirect_uri_not_in_allowed} ->
{:error,
dgettext(
"errors",
"The given redirect_uri is not in the list of allowed redirect URIs"
)}
end
end
def authorize(_parent, _args, _context) do
{:error, dgettext("errors", "You need to be logged-in to autorize applications")}
end
@spec get_application(any(), map(), Absinthe.Resolution.t()) ::
{:ok, Application.t()} | {:error, :not_found | :unauthenticated}
def get_application(_parent, %{client_id: client_id}, %{context: %{current_user: %User{}}}) do
case ApplicationManager.get_application_by_client_id(client_id) do
%Application{} = application ->
{:ok, application}
nil ->
{:error, :not_found}
end
end
def get_application(_parent, _args, _resolution) do
{:error, :unauthenticated}
end
def get_user_applications(_parent, _args, %{context: %{current_user: %User{id: user_id}}}) do
{:ok, ApplicationManager.list_application_tokens_for_user_id(user_id)}
end
def get_user_applications(_parent, _args, _resolution) do
{:error, :unauthenticated}
end
def revoke_application_token(_parent, %{app_token_id: app_token_id}, %{
context: %{current_user: %User{id: user_id}}
}) do
case ApplicationManager.get_application_token(app_token_id) do
%ApplicationToken{user_id: ^user_id} = app_token ->
case Applications.revoke_application_token(app_token) do
{:ok, %{delete_app_token: app_token, delete_guardian_tokens: _delete_guardian_tokens}} ->
{:ok, %{id: app_token.id}}
{:error, _, _, _} ->
{:error, dgettext("errors", "Error while revoking token")}
end
_ ->
{:error, :not_found}
end
end
def revoke_application_token(_parent, _args, _resolution) do
{:error, :unauthenticated}
end
end

View File

@@ -53,6 +53,7 @@ defmodule Mobilizon.GraphQL.Schema do
import_types(Schema.Users.PushSubscription)
import_types(Schema.Users.ActivitySetting)
import_types(Schema.FollowedGroupActivityType)
import_types(Schema.AuthApplicationType)
@desc "A struct containing the id of the deleted object"
object :deleted_object do
@@ -161,6 +162,7 @@ defmodule Mobilizon.GraphQL.Schema do
import_fields(:resource_queries)
import_fields(:post_queries)
import_fields(:statistics_queries)
import_fields(:auth_application_queries)
end
@desc """
@@ -187,6 +189,7 @@ defmodule Mobilizon.GraphQL.Schema do
import_fields(:follower_mutations)
import_fields(:push_mutations)
import_fields(:activity_setting_mutations)
import_fields(:auth_application_mutations)
end
@desc """

View File

@@ -0,0 +1,61 @@
defmodule Mobilizon.GraphQL.Schema.AuthApplicationType do
@moduledoc """
Schema representation for an auth application
"""
use Absinthe.Schema.Notation
alias Mobilizon.GraphQL.Resolvers.Application
@desc "An application"
object :auth_application do
field(:name, :string)
field(:client_id, :string)
field(:scopes, :string)
field(:website, :string)
end
@desc "An application"
object :auth_application_token do
field(:id, :id)
field(:inserted_at, :string)
field(:last_used_at, :string)
field(:application, :auth_application)
end
@desc "The informations returned after authorization"
object :application_code_and_state do
field(:code, :string)
field(:state, :string)
end
object :auth_application_queries do
@desc "Get an application"
field :auth_application, :auth_application do
arg(:client_id, non_null(:string), description: "The application's client_id")
resolve(&Application.get_application/3)
end
end
object :auth_application_mutations do
@desc "Authorize an application"
field :authorize_application, :application_code_and_state do
arg(:client_id, non_null(:string), description: "The application's client_id")
arg(:redirect_uri, non_null(:string),
description: "The URI to redirect to with the code and state"
)
arg(:scope, :string, description: "The scope for the authorization")
arg(:state, :string,
description: "A state parameter to check that the request wasn't altered"
)
resolve(&Application.authorize/3)
end
field :revoke_application_token, :deleted_object do
arg(:app_token_id, non_null(:string), description: "The application token's ID")
resolve(&Application.revoke_application_token/3)
end
end
end

View File

@@ -7,7 +7,7 @@ defmodule Mobilizon.GraphQL.Schema.UserType do
import Absinthe.Resolution.Helpers, only: [dataloader: 2]
alias Mobilizon.Events
alias Mobilizon.GraphQL.Resolvers.{Media, User}
alias Mobilizon.GraphQL.Resolvers.{Application, Media, User}
alias Mobilizon.GraphQL.Resolvers.Users.ActivitySettings
alias Mobilizon.GraphQL.Schema
@@ -161,6 +161,11 @@ defmodule Mobilizon.GraphQL.Schema.UserType do
resolve: &ActivitySettings.user_activity_settings/3,
description: "The user's activity settings"
)
field(:auth_authorized_applications, list_of(:auth_application_token),
resolve: &Application.get_user_applications/3,
description: "The user's authorized authentication apps"
)
end
@desc "The list of roles an user can have"