From 52c3f178a12cd714fe54397ddbb425518d374067 Mon Sep 17 00:00:00 2001 From: Ivan Ivanov Date: Wed, 20 Nov 2024 17:32:49 +0200 Subject: [PATCH 1/2] Expose metric registry for santiment team members outside of admin panel --- .../plug/santiment_team_member_only.ex | 43 +++++++++++++++++++ lib/sanbase_web/router.ex | 16 +++++++ 2 files changed, 59 insertions(+) create mode 100644 lib/sanbase_web/plug/santiment_team_member_only.ex diff --git a/lib/sanbase_web/plug/santiment_team_member_only.ex b/lib/sanbase_web/plug/santiment_team_member_only.ex new file mode 100644 index 0000000000..489c31ef5f --- /dev/null +++ b/lib/sanbase_web/plug/santiment_team_member_only.ex @@ -0,0 +1,43 @@ +defmodule SanbaseWeb.Plug.SantimentTeamMemberOnly do + @moduledoc ~s""" + Check if the container type allows access to the admin dashboard + endpoints. T + """ + + @behaviour Plug + + import Plug.Conn + + def init(opts), do: opts + + def call(conn, _) do + case get_in(conn.private, [:san_authentication, :auth, :current_user]) do + %Sanbase.Accounts.User{} = user -> + if santiment_member?(user) do + conn + else + conn + |> send_resp(403, "Unauthorized") + |> halt() + end + + _ -> + conn + |> send_resp(403, "Unauthorized") + |> halt() + end + end + + defp santiment_member?(%Sanbase.Accounts.User{} = user) do + cond do + has_san_team_role?(user) -> true + is_binary(user.email) and String.ends_with?(user.email, "@santiment.net") -> true + true -> false + end + end + + defp has_san_team_role?(user) do + user = Sanbase.Repo.preload(user, [:roles, roles: :role]) + Enum.any?(user.roles, &(&1.role.name in ["Santiment Team Member"])) + end +end diff --git a/lib/sanbase_web/router.ex b/lib/sanbase_web/router.ex index 65d7a16907..b8d6554d3a 100644 --- a/lib/sanbase_web/router.ex +++ b/lib/sanbase_web/router.ex @@ -6,6 +6,12 @@ defmodule SanbaseWeb.Router do plug(SanbaseWeb.Plug.AdminPodOnly) end + pipeline :santiment_user_access do + plug(SanbaseWeb.Graphql.AuthPlug) + plug(SanbaseWeb.Graphql.ContextPlug) + plug(SanbaseWeb.Plug.SantimentTeamMemberOnly) + end + pipeline :browser do plug(:accepts, ["html"]) plug(:fetch_session) @@ -50,6 +56,16 @@ defmodule SanbaseWeb.Router do get("/:provider/callback", AuthController, :callback) end + scope "/metric_registry", SanbaseWeb do + pipe_through([:browser, :santiment_user_access]) + + live("/", MetricRegistryIndexLive) + live("/change_suggestions", MetricRegistryChangeSuggestionsLive) + live("/show/:id", MetricRegistryShowLive) + live("/edit/:id", MetricRegistryFormLive, :edit) + live("/new", MetricRegistryFormLive, :new) + end + scope "/forms", SanbaseWeb do pipe_through(:browser) live("/", FormsLive) From 828ae6eda60c29882e7fb7bc3afaf10c79e278a3 Mon Sep 17 00:00:00 2001 From: Ivan Ivanov Date: Thu, 21 Nov 2024 17:21:27 +0200 Subject: [PATCH 2/2] backup --- lib/sanbase/accounts/user.ex | 13 +++++++++++-- .../metric_registry_form_live.ex | 2 +- .../plug/santiment_team_member_only.ex | 19 +++++++++++++------ lib/sanbase_web/router.ex | 1 - .../20241121133719_add_more_user_roles.exs | 19 +++++++++++++++++++ priv/repo/structure.sql | 1 + 6 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 priv/repo/migrations/20241121133719_add_more_user_roles.exs diff --git a/lib/sanbase/accounts/user.ex b/lib/sanbase/accounts/user.ex index 15b1a2197e..603b92d918 100644 --- a/lib/sanbase/accounts/user.ex +++ b/lib/sanbase/accounts/user.ex @@ -210,7 +210,12 @@ defmodule Sanbase.Accounts.User do def by_id(user_id, opts \\ []) def by_id(user_id, opts) when is_integer(user_id) do - query = from(u in __MODULE__, where: u.id == ^user_id) + # TODO: Make preload configurable via the opts + query = + from(u in __MODULE__, + where: u.id == ^user_id, + preload: [:eth_accounts, :user_settings, [roles: :role]] + ) query = case Keyword.get(opts, :lock_for_update, false) do @@ -230,7 +235,7 @@ defmodule Sanbase.Accounts.User do u in __MODULE__, where: u.id in ^user_ids, order_by: fragment("array_position(?, ?::int)", ^user_ids, u.id), - preload: [:eth_accounts, :user_settings] + preload: [:eth_accounts, :user_settings, [roles: :role]] ) |> Repo.all() @@ -324,6 +329,10 @@ defmodule Sanbase.Accounts.User do end end + def has_role?(%__MODULE__{roles: roles}, role) when is_list(roles) do + Enum.any?(roles, &(&1.role.name == role)) + end + def change_name(%__MODULE__{name: name} = user, name), do: {:ok, user} def change_name(%__MODULE__{} = user, name) do diff --git a/lib/sanbase_web/live/metric_registry/metric_registry_form_live.ex b/lib/sanbase_web/live/metric_registry/metric_registry_form_live.ex index 706d1bb6bd..17b4a8b46a 100644 --- a/lib/sanbase_web/live/metric_registry/metric_registry_form_live.ex +++ b/lib/sanbase_web/live/metric_registry/metric_registry_form_live.ex @@ -7,7 +7,7 @@ defmodule SanbaseWeb.MetricRegistryFormLive do alias SanbaseWeb.AvailableMetricsComponents @impl true - def mount(params, _session, socket) do + def mount(params, session, socket) do {:ok, metric_registry} = case socket.assigns.live_action do :new -> {:ok, %Registry{}} diff --git a/lib/sanbase_web/plug/santiment_team_member_only.ex b/lib/sanbase_web/plug/santiment_team_member_only.ex index 489c31ef5f..0af78d36f1 100644 --- a/lib/sanbase_web/plug/santiment_team_member_only.ex +++ b/lib/sanbase_web/plug/santiment_team_member_only.ex @@ -17,27 +17,34 @@ defmodule SanbaseWeb.Plug.SantimentTeamMemberOnly do conn else conn - |> send_resp(403, "Unauthorized") + |> send_resp(403, "Forbidden") |> halt() end _ -> conn - |> send_resp(403, "Unauthorized") + |> send_resp(403, "Forbidden") |> halt() end end defp santiment_member?(%Sanbase.Accounts.User{} = user) do cond do - has_san_team_role?(user) -> true + user_has_access_by_role?(user) -> true is_binary(user.email) and String.ends_with?(user.email, "@santiment.net") -> true true -> false end end - defp has_san_team_role?(user) do - user = Sanbase.Repo.preload(user, [:roles, roles: :role]) - Enum.any?(user.roles, &(&1.role.name in ["Santiment Team Member"])) + defp user_has_access_by_role?(user) do + Enum.any?( + user.roles, + &(&1.role.name in [ + "Santiment Team Member", + "Santiment WebPanel Viewer", + "Santiment WebPanel Editor", + "Santiment WebPanel Admin" + ]) + ) end end diff --git a/lib/sanbase_web/router.ex b/lib/sanbase_web/router.ex index b8d6554d3a..d716be6db5 100644 --- a/lib/sanbase_web/router.ex +++ b/lib/sanbase_web/router.ex @@ -8,7 +8,6 @@ defmodule SanbaseWeb.Router do pipeline :santiment_user_access do plug(SanbaseWeb.Graphql.AuthPlug) - plug(SanbaseWeb.Graphql.ContextPlug) plug(SanbaseWeb.Plug.SantimentTeamMemberOnly) end diff --git a/priv/repo/migrations/20241121133719_add_more_user_roles.exs b/priv/repo/migrations/20241121133719_add_more_user_roles.exs new file mode 100644 index 0000000000..e8e30bec5d --- /dev/null +++ b/priv/repo/migrations/20241121133719_add_more_user_roles.exs @@ -0,0 +1,19 @@ +defmodule Sanbase.Repo.Migrations.AddMoreUserRoles do + use Ecto.Migration + + def up do + execute(""" + INSERT INTO roles (id, name) VALUES + ((SELECT COALESCE(MAX(id), 0) + 1 FROM roles), 'Santiment WebPanel Viewer'), + ((SELECT COALESCE(MAX(id), 0) + 2 FROM roles), 'Santiment WebPanel Editor'), + ((SELECT COALESCE(MAX(id), 0) + 3 FROM roles), 'Santiment WebPanel Admin') + """) + end + + def down do + execute(""" + DELETE FROM roles + WHERE name IN ('Santiment WebPanel Viewer', 'Santiment WebPanel Editor', 'Santiment WebPanel Admin') + """) + end +end diff --git a/priv/repo/structure.sql b/priv/repo/structure.sql index 7d150a124e..acc0f6b52b 100644 --- a/priv/repo/structure.sql +++ b/priv/repo/structure.sql @@ -9622,3 +9622,4 @@ INSERT INTO public."schema_migrations" (version) VALUES (20241108112754); INSERT INTO public."schema_migrations" (version) VALUES (20241114140339); INSERT INTO public."schema_migrations" (version) VALUES (20241114141110); INSERT INTO public."schema_migrations" (version) VALUES (20241116104556); +INSERT INTO public."schema_migrations" (version) VALUES (20241121133719);