From 9ee83c8df77fe4d15691f265d6e301c6e3b93d29 Mon Sep 17 00:00:00 2001 From: Josh Kalderimis Date: Sat, 16 Dec 2023 13:59:49 +1300 Subject: [PATCH] add authorization to the Product Settings LiveView --- lib/nerves_hub/accounts.ex | 9 ++--- lib/nerves_hub_web.ex | 2 ++ lib/nerves_hub_web/helpers/authorization.ex | 17 ++++++++++ lib/nerves_hub_web/live/product/settings.ex | 19 +++++++++++ .../live/product/settings.html.heex | 33 +++++++++++++------ lib/nerves_hub_web/mounts/fetch_org_user.ex | 11 +++++++ lib/nerves_hub_web/router.ex | 1 + 7 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 lib/nerves_hub_web/helpers/authorization.ex create mode 100644 lib/nerves_hub_web/mounts/fetch_org_user.ex diff --git a/lib/nerves_hub/accounts.ex b/lib/nerves_hub/accounts.ex index 61408a7c3..7b4baf5b8 100644 --- a/lib/nerves_hub/accounts.ex +++ b/lib/nerves_hub/accounts.ex @@ -130,12 +130,9 @@ defmodule NervesHub.Accounts do end def get_org_user(org, user) do - from( - ou in OrgUser, - where: - ou.org_id == ^org.id and - ou.user_id == ^user.id - ) + OrgUser + |> where([ou], ou.org_id == ^org.id) + |> where([ou], ou.user_id == ^user.id) |> OrgUser.with_user() |> Repo.exclude_deleted() |> Repo.one() diff --git a/lib/nerves_hub_web.ex b/lib/nerves_hub_web.ex index 43807b877..847c6d846 100644 --- a/lib/nerves_hub_web.ex +++ b/lib/nerves_hub_web.ex @@ -116,6 +116,8 @@ defmodule NervesHubWeb do # Translation import NervesHubWeb.Gettext + import NervesHub.Helpers.Authorization + # Shortcut for generating JS commands alias Phoenix.LiveView.JS diff --git a/lib/nerves_hub_web/helpers/authorization.ex b/lib/nerves_hub_web/helpers/authorization.ex new file mode 100644 index 000000000..66be49c28 --- /dev/null +++ b/lib/nerves_hub_web/helpers/authorization.ex @@ -0,0 +1,17 @@ +defmodule NervesHub.Helpers.Authorization do + alias NervesHub.Accounts.OrgUser + alias NervesHub.Accounts.User + + def authorized!(org_user, permission) do + true = authorized?(org_user, permission) + end + + def authorized?(:update_product, %OrgUser{role: user_role}), do: role_check(:write, user_role) + def authorized?(:delete_product, %OrgUser{role: user_role}), do: role_check(:admin, user_role) + + defp role_check(required_role, user_role) do + required_role + |> User.role_or_higher() + |> Enum.any?(&(&1 == user_role)) + end +end diff --git a/lib/nerves_hub_web/live/product/settings.ex b/lib/nerves_hub_web/live/product/settings.ex index 8eb6e33d2..2a6785bf6 100644 --- a/lib/nerves_hub_web/live/product/settings.ex +++ b/lib/nerves_hub_web/live/product/settings.ex @@ -15,6 +15,8 @@ defmodule NervesHubWeb.Live.Product.Settings do end def handle_event("delta-updated", %{"delta_updatable" => delta}, socket) do + authorized!(:update_product, socket.assigns.org_user) + attrs = %{delta_updatable: delta == "true"} {:ok, product} = Products.update_product(socket.assigns.product, attrs) @@ -23,6 +25,8 @@ defmodule NervesHubWeb.Live.Product.Settings do end def handle_event("add-shared-secret", _params, socket) do + authorized!(:update_product, socket.assigns.org_user) + {:ok, _} = Products.create_shared_secret_auth(socket.assigns.product) refreshed = Products.load_shared_secret_auth(socket.assigns.product) @@ -40,6 +44,8 @@ defmodule NervesHubWeb.Live.Product.Settings do end def handle_event("deactivate-shared-secret", %{"shared_secret_id" => shared_secret_id}, socket) do + authorized!(:update_product, socket.assigns.org_user) + product = socket.assigns.product {:ok, _} = Products.deactivate_shared_secret_auth(product, shared_secret_id) @@ -48,4 +54,17 @@ defmodule NervesHubWeb.Live.Product.Settings do {:reply, assign(socket, :shared_secrets, refreshed.shared_secret_auth)} end + + def handle_event("delete-product", _parmas, socket) do + authorized!(:delete_product, socket.assigns.org_user) + + with {:ok, _product} <- Products.delete_product(socket.assigns.product) do + socket = + socket + |> put_flash(:info, "Product deleted successfully.") + |> redirect(to: "/org/#{socket.assigns.org.name}") + + {:noreply, socket} + end + end end diff --git a/lib/nerves_hub_web/live/product/settings.html.heex b/lib/nerves_hub_web/live/product/settings.html.heex index 4a2809a19..e518f3cc7 100644 --- a/lib/nerves_hub_web/live/product/settings.html.heex +++ b/lib/nerves_hub_web/live/product/settings.html.heex @@ -27,7 +27,16 @@
- + @@ -91,7 +100,14 @@ - @@ -103,10 +119,10 @@
- -
@@ -118,10 +134,7 @@
- <%= link("Remove Product", - class: "btn btn-primary", - to: ~p"/org/#{@org.name}/#{@product.name}", - method: :delete, - data: [confirm: "Are you sure you want to delete this product? This can not be undone."] - ) %> +
diff --git a/lib/nerves_hub_web/mounts/fetch_org_user.ex b/lib/nerves_hub_web/mounts/fetch_org_user.ex new file mode 100644 index 000000000..2113ded99 --- /dev/null +++ b/lib/nerves_hub_web/mounts/fetch_org_user.ex @@ -0,0 +1,11 @@ +defmodule NervesHubWeb.Mounts.FetchOrgUser do + import Phoenix.Component + + alias NervesHub.Accounts + + def on_mount(_, _, _, socket) do + {:ok, org_user} = Accounts.get_org_user(socket.assigns.org, socket.assigns.user) + + {:cont, assign(socket, :org_user, org_user)} + end +end diff --git a/lib/nerves_hub_web/router.ex b/lib/nerves_hub_web/router.ex index 48797493a..43e85be5f 100644 --- a/lib/nerves_hub_web/router.ex +++ b/lib/nerves_hub_web/router.ex @@ -256,6 +256,7 @@ defmodule NervesHubWeb.Router do NervesHubWeb.Mounts.AccountAuth, NervesHubWeb.Mounts.CurrentPath, NervesHubWeb.Mounts.FetchOrg, + NervesHubWeb.Mounts.FetchOrgUser, NervesHubWeb.Mounts.FetchProduct ] do live("/settings", Live.Product.Settings)