Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 19 additions & 6 deletions lib/query_canary/checks.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ defmodule QueryCanary.Checks do

alias QueryCanary.Checks.{Check, CheckResult}
alias QueryCanary.Accounts.{User, Scope, TeamUser}
alias QueryCanary.Accounts
alias QueryCanary.Connections.ConnectionManager
alias QueryCanary.Checks.CheckNotifier

Expand Down Expand Up @@ -37,29 +38,41 @@ defmodule QueryCanary.Checks do

# Public, we can view no matter what
def can_perform?(:view, _, %QueryCanary.Checks.Check{public: true}), do: true
# If not public, only if we're the scoped user
# If not public, only if we're the scoped user or member of owning team
def can_perform?(
:view,
%QueryCanary.Accounts.Scope{} = scope,
%QueryCanary.Checks.Check{} = check
) do
server_ids = QueryCanary.Servers.list_servers(scope) |> Enum.map(fn s -> s.id end)
check = Repo.preload(check, server: [:team])

check.server_id in server_ids
cond do
is_nil(check.server.team_id) ->
check.user_id == scope.user.id

true ->
Accounts.user_has_access_to_team?(scope.user.id, check.server.team_id)
end
end

# No one can edit
def can_perform?(:edit, nil, _), do: false

# Unless you are the scoped user
# Unless you are the owner or team member (for edit restrict maybe admin)
def can_perform?(
:edit,
%QueryCanary.Accounts.Scope{} = scope,
%QueryCanary.Checks.Check{} = check
) do
server_ids = QueryCanary.Servers.list_servers(scope) |> Enum.map(fn s -> s.id end)
check = Repo.preload(check, server: [:team])

check.server_id in server_ids
cond do
is_nil(check.server.team_id) ->
check.user_id == scope.user.id

true ->
Accounts.user_has_access_to_team?(scope.user.id, check.server.team_id)
end
end

def can_perform?(_, _, _), do: false
Expand Down
15 changes: 14 additions & 1 deletion lib/query_canary_web/check_auth.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ defmodule QueryCanaryWeb.CheckAuth do

alias QueryCanary.Checks

def on_mount(:default, %{"id" => check_id}, _session, socket) do
def on_mount(:view, %{"id" => check_id}, _session, socket) do
with %QueryCanary.Checks.Check{} = check <- Checks.get_possibly_public_check(check_id),
true <- Checks.can_perform?(:view, socket.assigns.current_scope, check) do
{:cont, assign(socket, :check, check)}
Expand All @@ -16,4 +16,17 @@ defmodule QueryCanaryWeb.CheckAuth do
|> redirect(to: "/")}
end
end

def on_mount(:edit, %{"id" => check_id}, _session, socket) do
with %QueryCanary.Checks.Check{} = check <- Checks.get_possibly_public_check(check_id),
true <- Checks.can_perform?(:edit, socket.assigns.current_scope, check) do
{:cont, assign(socket, :check, check)}
else
_ ->
{:halt,
socket
|> put_flash(:error, "You don't have permission to access this check!")
|> redirect(to: "/")}
end
end
end
2 changes: 2 additions & 0 deletions lib/query_canary_web/live/check_live/form.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ defmodule QueryCanaryWeb.CheckLive.Form do
alias QueryCanary.Checks
alias QueryCanary.Checks.Check

on_mount {QueryCanaryWeb.CheckAuth, :edit}

@impl true
def render(assigns) do
~H"""
Expand Down
2 changes: 1 addition & 1 deletion lib/query_canary_web/live/check_live/show.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defmodule QueryCanaryWeb.CheckLive.Show do

import QueryCanaryWeb.Components.CheckAnalysis

on_mount QueryCanaryWeb.CheckAuth
on_mount {QueryCanaryWeb.CheckAuth, :view}

@impl true
def render(assigns) do
Expand Down
24 changes: 24 additions & 0 deletions test/query_canary_web/live/check_live_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ defmodule QueryCanaryWeb.CheckLiveTest do

import Phoenix.LiveViewTest
import QueryCanary.ChecksFixtures
import QueryCanary.AccountsFixtures

@update_attrs %{
name: "Updated Check",
Expand Down Expand Up @@ -100,4 +101,27 @@ defmodule QueryCanaryWeb.CheckLiveTest do
assert html =~ "Updated Check"
end
end

describe "Permissions" do
test "cannot view another user's private check", %{conn: conn, scope: _scope} do
other_scope = user_scope_fixture()
other_check = check_fixture(other_scope)

# Attempt to load other user's check
assert {:error, {:redirect, %{to: redirected_to}}} = live(conn, ~p"/checks/#{other_check}")
# expecting redirect to index or auth page
assert redirected_to =~ "/"
end

test "cannot edit another user's check", %{conn: conn, scope: _scope} do
other_scope = user_scope_fixture()
other_check = check_fixture(other_scope)

# Try direct edit route
assert {:error, {:redirect, %{to: redirected_to}}} =
live(conn, ~p"/checks/#{other_check}/edit")

assert redirected_to =~ "/"
end
end
end