mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
refactor(portal): hard delete data (#9694)
This commit is contained in:
@@ -61,7 +61,7 @@ defmodule API.Client.Channel do
|
||||
socket = Debouncer.cache_stamp_secrets(socket, relays)
|
||||
|
||||
# Track client's presence
|
||||
:ok = Clients.Presence.connect(socket.assigns.client)
|
||||
:ok = Clients.Presence.connect(socket.assigns.client, socket.assigns.subject.token_id)
|
||||
|
||||
# Subscribe to all account updates
|
||||
:ok = PubSub.Account.subscribe(socket.assigns.client.account_id)
|
||||
|
||||
@@ -95,7 +95,7 @@ defmodule API.GatewayController do
|
||||
def delete(conn, %{"id" => id}) do
|
||||
subject = conn.assigns.subject
|
||||
|
||||
with {:ok, gateway} <- Gateways.fetch_gateway_by_id(id, subject),
|
||||
with {:ok, gateway} <- Gateways.fetch_gateway_by_id(id, subject, preload: :online?),
|
||||
{:ok, gateway} <- Gateways.delete_gateway(gateway, subject) do
|
||||
render(conn, :show, gateway: gateway)
|
||||
end
|
||||
|
||||
@@ -212,8 +212,8 @@ defmodule API.GatewayGroupController do
|
||||
subject = conn.assigns.subject
|
||||
|
||||
with {:ok, gateway_group} <- Gateways.fetch_group_by_id(gateway_group_id, subject),
|
||||
{:ok, deleted_tokens} <- Tokens.delete_tokens_for(gateway_group, subject) do
|
||||
render(conn, :deleted_tokens, %{tokens: deleted_tokens})
|
||||
{:ok, deleted_count} <- Tokens.delete_tokens_for(gateway_group, subject) do
|
||||
render(conn, :deleted_tokens, %{count: deleted_count})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -45,8 +45,8 @@ defmodule API.GatewayGroupJSON do
|
||||
@doc """
|
||||
Render all deleted Gateway Group Tokens
|
||||
"""
|
||||
def deleted_tokens(%{tokens: tokens}) do
|
||||
%{data: for(token <- tokens, do: %{id: token.id})}
|
||||
def deleted_tokens(%{count: count}) do
|
||||
%{data: %{deleted_count: count}}
|
||||
end
|
||||
|
||||
defp data(%Gateways.Group{} = group) do
|
||||
|
||||
@@ -73,8 +73,7 @@ defmodule API.IdentityProviderController do
|
||||
def delete(conn, %{"id" => id}) do
|
||||
subject = conn.assigns.subject
|
||||
|
||||
with {:ok, identity_provider} <- Auth.fetch_provider_by_id(id, subject),
|
||||
{:ok, identity_provider} <- Auth.delete_provider(identity_provider, subject) do
|
||||
with {:ok, identity_provider} <- Auth.delete_provider_by_id(id, subject) do
|
||||
render(conn, :show, identity_provider: identity_provider)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -40,7 +40,7 @@ defmodule API.Gateway.Channel do
|
||||
Process.send_after(self(), :prune_cache, @prune_cache_every)
|
||||
|
||||
# Track gateway's presence
|
||||
:ok = Gateways.Presence.connect(socket.assigns.gateway)
|
||||
:ok = Gateways.Presence.connect(socket.assigns.gateway, socket.assigns.token_id)
|
||||
|
||||
# Subscribe to all account updates
|
||||
:ok = PubSub.Account.subscribe(socket.assigns.gateway.account_id)
|
||||
|
||||
@@ -19,7 +19,7 @@ defmodule API.Gateway.Socket do
|
||||
attrs = Map.take(attrs, ~w[external_id name public_key])
|
||||
|
||||
with {:ok, group, token} <- Gateways.authenticate(encoded_token, context),
|
||||
{:ok, gateway} <- Gateways.upsert_gateway(group, token, attrs, context) do
|
||||
{:ok, gateway} <- Gateways.upsert_gateway(group, attrs, context) do
|
||||
OpenTelemetry.Tracer.set_attributes(%{
|
||||
token_id: token.id,
|
||||
gateway_id: gateway.id,
|
||||
|
||||
@@ -42,7 +42,7 @@ defmodule API.Relay.Channel do
|
||||
|
||||
OpenTelemetry.Tracer.with_span "relay.after_join" do
|
||||
push(socket, "init", %{})
|
||||
:ok = Relays.connect_relay(socket.assigns.relay, stamp_secret)
|
||||
:ok = Relays.connect_relay(socket.assigns.relay, stamp_secret, socket.assigns.token_id)
|
||||
{:noreply, socket}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,7 +19,7 @@ defmodule API.Relay.Socket do
|
||||
attrs = Map.take(attrs, ~w[ipv4 ipv6 name port])
|
||||
|
||||
with {:ok, group, token} <- Relays.authenticate(encoded_token, context),
|
||||
{:ok, relay} <- Relays.upsert_relay(group, token, attrs, context) do
|
||||
{:ok, relay} <- Relays.upsert_relay(group, attrs, context) do
|
||||
OpenTelemetry.Tracer.set_attributes(%{
|
||||
token_id: token.id,
|
||||
relay_id: relay.id,
|
||||
|
||||
@@ -65,7 +65,6 @@ defmodule API.Schemas.GatewayGroupToken do
|
||||
defmodule DeletedTokens do
|
||||
require OpenApiSpex
|
||||
alias OpenApiSpex.Schema
|
||||
alias API.Schemas.GatewayGroupToken
|
||||
|
||||
OpenApiSpex.schema(%{
|
||||
title: "DeletedGatewayGroupTokenListResponse",
|
||||
@@ -73,20 +72,20 @@ defmodule API.Schemas.GatewayGroupToken do
|
||||
type: :object,
|
||||
properties: %{
|
||||
data: %Schema{
|
||||
description: "Deleted Gateway Group Tokens",
|
||||
type: :array,
|
||||
items: GatewayGroupToken.Schema
|
||||
type: :object,
|
||||
properties: %{
|
||||
deleted_count: %Schema{
|
||||
type: :integer,
|
||||
description: "Number of tokens that were deleted"
|
||||
}
|
||||
},
|
||||
required: [:deleted_count]
|
||||
}
|
||||
},
|
||||
example: %{
|
||||
"data" => [
|
||||
%{
|
||||
"id" => "42a7f82f-831a-4a9d-8f17-c66c2bb6e205"
|
||||
},
|
||||
%{
|
||||
"id" => "6301d7d2-4938-4123-87de-282c01cca656"
|
||||
}
|
||||
]
|
||||
"data" => %{
|
||||
"deleted_count" => 5
|
||||
}
|
||||
}
|
||||
})
|
||||
end
|
||||
|
||||
@@ -135,6 +135,17 @@ defmodule API.Client.ChannelTest do
|
||||
|
||||
subject = %{subject | expires_at: expires_at}
|
||||
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
|
||||
global_relay =
|
||||
Fixtures.Relays.create_relay(
|
||||
group: global_relay_group,
|
||||
last_seen_remote_ip_location_lat: 37,
|
||||
last_seen_remote_ip_location_lon: -120
|
||||
)
|
||||
|
||||
global_relay_token = Fixtures.Relays.create_global_token(group: global_relay_group)
|
||||
|
||||
{:ok, _reply, socket} =
|
||||
API.Client.Socket
|
||||
|> socket("client:#{client.id}", %{
|
||||
@@ -166,6 +177,9 @@ defmodule API.Client.ChannelTest do
|
||||
offline_resource: offline_resource,
|
||||
dns_resource_policy: dns_resource_policy,
|
||||
internet_resource_policy: internet_resource_policy,
|
||||
global_relay_group: global_relay_group,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token,
|
||||
socket: socket
|
||||
}
|
||||
end
|
||||
@@ -467,7 +481,8 @@ defmodule API.Client.ChannelTest do
|
||||
|
||||
relay1 = Fixtures.Relays.create_relay(group: relay_group)
|
||||
stamp_secret1 = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1, relay_token.id)
|
||||
|
||||
Fixtures.Relays.update_relay(relay1,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second),
|
||||
@@ -477,7 +492,7 @@ defmodule API.Client.ChannelTest do
|
||||
|
||||
relay2 = Fixtures.Relays.create_relay(group: relay_group)
|
||||
stamp_secret2 = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay2, stamp_secret2)
|
||||
:ok = Domain.Relays.connect_relay(relay2, stamp_secret2, relay_token.id)
|
||||
|
||||
Fixtures.Relays.update_relay(relay2,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-100, :second),
|
||||
@@ -544,7 +559,8 @@ defmodule API.Client.ChannelTest do
|
||||
|
||||
assert_push "init", %{relays: []}
|
||||
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret, relay_token.id)
|
||||
|
||||
assert_push "relays_presence",
|
||||
%{
|
||||
@@ -570,7 +586,7 @@ defmodule API.Client.ChannelTest do
|
||||
last_seen_remote_ip_location_lon: -120.0
|
||||
)
|
||||
|
||||
:ok = Domain.Relays.connect_relay(other_relay, stamp_secret)
|
||||
:ok = Domain.Relays.connect_relay(other_relay, stamp_secret, relay_token.id)
|
||||
other_relay_id = other_relay.id
|
||||
|
||||
refute_push "relays_presence",
|
||||
@@ -589,7 +605,8 @@ defmodule API.Client.ChannelTest do
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
|
||||
relay1 = Fixtures.Relays.create_relay(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret, relay_token.id)
|
||||
|
||||
Fixtures.Relays.update_relay(relay1,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second),
|
||||
@@ -715,7 +732,8 @@ defmodule API.Client.ChannelTest do
|
||||
|
||||
relay1 = Fixtures.Relays.create_relay(group: relay_group)
|
||||
stamp_secret1 = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1, relay_token.id)
|
||||
|
||||
assert_push "relays_presence",
|
||||
%{
|
||||
@@ -733,7 +751,7 @@ defmodule API.Client.ChannelTest do
|
||||
Process.sleep(1)
|
||||
|
||||
# Reconnect with the same stamp secret
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1, relay_token.id)
|
||||
|
||||
# Should not receive any disconnect
|
||||
relay_id = relay1.id
|
||||
@@ -751,7 +769,8 @@ defmodule API.Client.ChannelTest do
|
||||
|
||||
relay1 = Fixtures.Relays.create_relay(group: relay_group)
|
||||
stamp_secret1 = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1, relay_token.id)
|
||||
|
||||
assert_push "relays_presence",
|
||||
%{
|
||||
@@ -770,7 +789,7 @@ defmodule API.Client.ChannelTest do
|
||||
|
||||
# Reconnect with a different stamp secret
|
||||
stamp_secret2 = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret2)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret2, relay_token.id)
|
||||
|
||||
# Should receive disconnect "immediately"
|
||||
assert_push "relays_presence",
|
||||
@@ -790,7 +809,8 @@ defmodule API.Client.ChannelTest do
|
||||
|
||||
relay1 = Fixtures.Relays.create_relay(group: relay_group)
|
||||
stamp_secret1 = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1, relay_token.id)
|
||||
|
||||
assert_push "relays_presence",
|
||||
%{
|
||||
@@ -2023,19 +2043,12 @@ defmodule API.Client.ChannelTest do
|
||||
|
||||
test "returns error when all gateways are offline", %{
|
||||
dns_resource: resource,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token,
|
||||
socket: socket
|
||||
} do
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
|
||||
global_relay =
|
||||
Fixtures.Relays.create_relay(
|
||||
group: global_relay_group,
|
||||
last_seen_remote_ip_location_lat: 37,
|
||||
last_seen_remote_ip_location_lon: -120
|
||||
)
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret)
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret, global_relay_token.id)
|
||||
|
||||
push(socket, "create_flow", %{
|
||||
"resource_id" => resource.id,
|
||||
@@ -2052,8 +2065,9 @@ defmodule API.Client.ChannelTest do
|
||||
} do
|
||||
resource = Fixtures.Resources.create_resource(account: account)
|
||||
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account) |> Repo.preload(:group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
attrs = %{
|
||||
"resource_id" => resource.id,
|
||||
@@ -2120,7 +2134,9 @@ defmodule API.Client.ChannelTest do
|
||||
"connected_gateway_ids" => []
|
||||
}
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
push(socket, "create_flow", attrs)
|
||||
|
||||
@@ -2137,8 +2153,9 @@ defmodule API.Client.ChannelTest do
|
||||
dns_resource: resource,
|
||||
socket: socket
|
||||
} do
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account) |> Repo.preload(:group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
push(socket, "create_flow", %{
|
||||
"resource_id" => resource.id,
|
||||
@@ -2160,26 +2177,19 @@ defmodule API.Client.ChannelTest do
|
||||
client: client,
|
||||
gateway_group_token: gateway_group_token,
|
||||
gateway: gateway,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token,
|
||||
socket: socket
|
||||
} do
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
|
||||
global_relay =
|
||||
Fixtures.Relays.create_relay(
|
||||
group: global_relay_group,
|
||||
last_seen_remote_ip_location_lat: 37,
|
||||
last_seen_remote_ip_location_lon: -120
|
||||
)
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret)
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret, global_relay_token.id)
|
||||
|
||||
Fixtures.Relays.update_relay(global_relay,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
)
|
||||
|
||||
:ok = PubSub.Account.subscribe(gateway.account_id)
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_group_token.id)
|
||||
:ok = PubSub.subscribe(Domain.Tokens.socket_id(gateway_group_token))
|
||||
|
||||
# Prime cache
|
||||
@@ -2218,6 +2228,8 @@ defmodule API.Client.ChannelTest do
|
||||
internet_gateway: gateway,
|
||||
internet_resource: resource,
|
||||
client: client,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token,
|
||||
socket: socket
|
||||
} do
|
||||
Fixtures.Accounts.update_account(account,
|
||||
@@ -2226,17 +2238,8 @@ defmodule API.Client.ChannelTest do
|
||||
}
|
||||
)
|
||||
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
|
||||
global_relay =
|
||||
Fixtures.Relays.create_relay(
|
||||
group: global_relay_group,
|
||||
last_seen_remote_ip_location_lat: 37,
|
||||
last_seen_remote_ip_location_lon: -120
|
||||
)
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret)
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret, global_relay_token.id)
|
||||
|
||||
:ok = PubSub.Account.subscribe(account.id)
|
||||
|
||||
@@ -2244,7 +2247,9 @@ defmodule API.Client.ChannelTest do
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
PubSub.subscribe(Domain.Tokens.socket_id(gateway_group_token))
|
||||
|
||||
send(socket.channel_pid, {:created, resource})
|
||||
@@ -2282,19 +2287,12 @@ defmodule API.Client.ChannelTest do
|
||||
gateway_group_token: gateway_group_token,
|
||||
gateway: gateway,
|
||||
subject: subject,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token,
|
||||
socket: socket
|
||||
} do
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
|
||||
global_relay =
|
||||
Fixtures.Relays.create_relay(
|
||||
group: global_relay_group,
|
||||
last_seen_remote_ip_location_lat: 37,
|
||||
last_seen_remote_ip_location_lon: -120
|
||||
)
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret)
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret, global_relay_token.id)
|
||||
:ok = PubSub.Account.subscribe(gateway.account_id)
|
||||
|
||||
send(socket.channel_pid, {:created, resource})
|
||||
@@ -2305,7 +2303,7 @@ defmodule API.Client.ChannelTest do
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_group_token.id)
|
||||
PubSub.subscribe(Domain.Tokens.socket_id(gateway_group_token))
|
||||
|
||||
push(socket, "create_flow", %{
|
||||
@@ -2383,6 +2381,8 @@ defmodule API.Client.ChannelTest do
|
||||
membership: membership,
|
||||
gateway: gateway,
|
||||
gateway_group_token: gateway_group_token,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token,
|
||||
actor_group: actor_group
|
||||
} do
|
||||
actor = Fixtures.Actors.create_actor(type: :service_account, account: account)
|
||||
@@ -2400,23 +2400,16 @@ defmodule API.Client.ChannelTest do
|
||||
})
|
||||
|> subscribe_and_join(API.Client.Channel, "client")
|
||||
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
|
||||
global_relay =
|
||||
Fixtures.Relays.create_relay(
|
||||
group: global_relay_group,
|
||||
last_seen_remote_ip_location_lat: 37,
|
||||
last_seen_remote_ip_location_lon: -120
|
||||
)
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret)
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret, global_relay_token.id)
|
||||
|
||||
Fixtures.Relays.update_relay(global_relay,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
PubSub.subscribe(Domain.Tokens.socket_id(gateway_group_token))
|
||||
|
||||
:ok = PubSub.Account.subscribe(account.id)
|
||||
@@ -2443,20 +2436,13 @@ defmodule API.Client.ChannelTest do
|
||||
membership: membership,
|
||||
subject: subject,
|
||||
client: client,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token,
|
||||
socket: socket
|
||||
} do
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
:ok = Domain.Relays.connect_relay(global_relay, Ecto.UUID.generate(), global_relay_token.id)
|
||||
|
||||
relay =
|
||||
Fixtures.Relays.create_relay(
|
||||
group: global_relay_group,
|
||||
last_seen_remote_ip_location_lat: 37,
|
||||
last_seen_remote_ip_location_lon: -120
|
||||
)
|
||||
|
||||
:ok = Domain.Relays.connect_relay(relay, Ecto.UUID.generate())
|
||||
|
||||
Fixtures.Relays.update_relay(relay,
|
||||
Fixtures.Relays.update_relay(global_relay,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
)
|
||||
|
||||
@@ -2472,8 +2458,10 @@ defmodule API.Client.ChannelTest do
|
||||
user_agent: "Linux/24.04 connlib/1.0.412"
|
||||
)
|
||||
)
|
||||
|> Repo.preload(:group)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
:ok = PubSub.Account.subscribe(account.id)
|
||||
|
||||
@@ -2525,8 +2513,10 @@ defmodule API.Client.ChannelTest do
|
||||
user_agent: "Linux/24.04 connlib/1.4.11"
|
||||
)
|
||||
)
|
||||
|> Repo.preload(:group)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
push(socket, "create_flow", %{
|
||||
"resource_id" => resource.id,
|
||||
@@ -2544,20 +2534,13 @@ defmodule API.Client.ChannelTest do
|
||||
dns_resource: resource,
|
||||
dns_resource_policy: policy,
|
||||
membership: membership,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token,
|
||||
socket: socket
|
||||
} do
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
:ok = Domain.Relays.connect_relay(global_relay, Ecto.UUID.generate(), global_relay_token.id)
|
||||
|
||||
relay =
|
||||
Fixtures.Relays.create_relay(
|
||||
group: global_relay_group,
|
||||
last_seen_remote_ip_location_lat: 37,
|
||||
last_seen_remote_ip_location_lon: -120
|
||||
)
|
||||
|
||||
:ok = Domain.Relays.connect_relay(relay, Ecto.UUID.generate())
|
||||
|
||||
Fixtures.Relays.update_relay(relay,
|
||||
Fixtures.Relays.update_relay(global_relay,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
)
|
||||
|
||||
@@ -2566,8 +2549,10 @@ defmodule API.Client.ChannelTest do
|
||||
account: account,
|
||||
group: gateway_group
|
||||
)
|
||||
|> Repo.preload(:group)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway1)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway1.group)
|
||||
:ok = Gateways.Presence.connect(gateway1, gateway_token.id)
|
||||
|
||||
gateway2 =
|
||||
Fixtures.Gateways.create_gateway(
|
||||
@@ -2575,7 +2560,7 @@ defmodule API.Client.ChannelTest do
|
||||
group: gateway_group
|
||||
)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway2)
|
||||
:ok = Gateways.Presence.connect(gateway2, gateway_token.id)
|
||||
|
||||
:ok = PubSub.Account.subscribe(account.id)
|
||||
|
||||
@@ -2629,10 +2614,7 @@ defmodule API.Client.ChannelTest do
|
||||
assert_reply ref, :error, %{reason: :offline}
|
||||
end
|
||||
|
||||
test "returns error when all gateways are offline", %{
|
||||
dns_resource: resource,
|
||||
socket: socket
|
||||
} do
|
||||
test "returns error when all gateways are offline", %{dns_resource: resource, socket: socket} do
|
||||
ref = push(socket, "prepare_connection", %{"resource_id" => resource.id})
|
||||
assert_reply ref, :error, %{reason: :offline}
|
||||
end
|
||||
@@ -2643,8 +2625,9 @@ defmodule API.Client.ChannelTest do
|
||||
} do
|
||||
resource = Fixtures.Resources.create_resource(account: account)
|
||||
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account) |> Repo.preload(:group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
attrs = %{
|
||||
"resource_id" => resource.id
|
||||
@@ -2659,35 +2642,32 @@ defmodule API.Client.ChannelTest do
|
||||
dns_resource: resource,
|
||||
socket: socket
|
||||
} do
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account) |> Repo.preload(:group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
ref = push(socket, "prepare_connection", %{"resource_id" => resource.id})
|
||||
assert_reply ref, :error, %{reason: :offline}
|
||||
end
|
||||
|
||||
test "returns online gateway connected to the resource", %{
|
||||
account: account,
|
||||
dns_resource: resource,
|
||||
gateway: gateway,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token,
|
||||
socket: socket
|
||||
} do
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
|
||||
global_relay =
|
||||
Fixtures.Relays.create_relay(
|
||||
group: global_relay_group,
|
||||
last_seen_remote_ip_location_lat: 37,
|
||||
last_seen_remote_ip_location_lon: -120
|
||||
)
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret)
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret, global_relay_token.id)
|
||||
|
||||
Fixtures.Relays.update_relay(global_relay,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
ref = push(socket, "prepare_connection", %{"resource_id" => resource.id})
|
||||
resource_id = resource.id
|
||||
@@ -2708,8 +2688,9 @@ defmodule API.Client.ChannelTest do
|
||||
internet_resource: internet_resource,
|
||||
socket: socket
|
||||
} do
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account) |> Repo.preload(:group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
ref = push(socket, "prepare_connection", %{"resource_id" => dns_resource.id})
|
||||
assert_reply ref, :error, %{reason: :offline}
|
||||
@@ -2722,12 +2703,12 @@ defmodule API.Client.ChannelTest do
|
||||
account: account,
|
||||
actor_group: actor_group,
|
||||
membership: membership,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token,
|
||||
socket: socket
|
||||
} do
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
global_relay = Fixtures.Relays.create_relay(group: global_relay_group)
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret)
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret, global_relay_token.id)
|
||||
|
||||
Fixtures.Relays.update_relay(global_relay,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
@@ -2743,6 +2724,7 @@ defmodule API.Client.ChannelTest do
|
||||
user_agent: "iOS/12.5 (iPhone) connlib/1.1.0"
|
||||
}
|
||||
)
|
||||
|> Repo.preload(:group)
|
||||
|
||||
resource =
|
||||
Fixtures.Resources.create_resource(
|
||||
@@ -2758,7 +2740,8 @@ defmodule API.Client.ChannelTest do
|
||||
resource: resource
|
||||
)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
ref = push(socket, "prepare_connection", %{"resource_id" => resource.id})
|
||||
resource_id = resource.id
|
||||
@@ -2773,12 +2756,14 @@ defmodule API.Client.ChannelTest do
|
||||
user_agent: "iOS/12.5 (iPhone) connlib/1.2.0"
|
||||
}
|
||||
)
|
||||
|> Repo.preload(:group)
|
||||
|
||||
Fixtures.Relays.update_relay(global_relay,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
:ok = PubSub.Account.subscribe(account.id)
|
||||
|
||||
send(socket.channel_pid, %Changes.Change{
|
||||
@@ -2815,6 +2800,8 @@ defmodule API.Client.ChannelTest do
|
||||
account: account,
|
||||
internet_gateway_group: internet_gateway_group,
|
||||
internet_resource: resource,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token,
|
||||
socket: socket
|
||||
} do
|
||||
account =
|
||||
@@ -2824,10 +2811,8 @@ defmodule API.Client.ChannelTest do
|
||||
}
|
||||
)
|
||||
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
global_relay = Fixtures.Relays.create_relay(group: global_relay_group)
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret)
|
||||
:ok = Domain.Relays.connect_relay(global_relay, stamp_secret, global_relay_token.id)
|
||||
|
||||
Fixtures.Relays.update_relay(global_relay,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
@@ -2841,8 +2826,10 @@ defmodule API.Client.ChannelTest do
|
||||
user_agent: "iOS/12.5 (iPhone) connlib/1.2.0"
|
||||
}
|
||||
)
|
||||
|> Repo.preload(:group)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
ref = push(socket, "prepare_connection", %{"resource_id" => resource.id})
|
||||
resource_id = resource.id
|
||||
@@ -2857,12 +2844,14 @@ defmodule API.Client.ChannelTest do
|
||||
user_agent: "iOS/12.5 (iPhone) connlib/1.3.0"
|
||||
}
|
||||
)
|
||||
|> Repo.preload(:group)
|
||||
|
||||
Fixtures.Relays.update_relay(global_relay,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
ref = push(socket, "prepare_connection", %{"resource_id" => resource.id})
|
||||
|
||||
@@ -2880,6 +2869,8 @@ defmodule API.Client.ChannelTest do
|
||||
account: account,
|
||||
dns_resource: resource,
|
||||
gateway: gateway,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token,
|
||||
actor_group: actor_group
|
||||
} do
|
||||
actor = Fixtures.Actors.create_actor(type: :service_account, account: account)
|
||||
@@ -2897,22 +2888,15 @@ defmodule API.Client.ChannelTest do
|
||||
})
|
||||
|> subscribe_and_join(API.Client.Channel, "client")
|
||||
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
:ok = Domain.Relays.connect_relay(global_relay, Ecto.UUID.generate(), global_relay_token.id)
|
||||
|
||||
relay =
|
||||
Fixtures.Relays.create_relay(
|
||||
group: global_relay_group,
|
||||
last_seen_remote_ip_location_lat: 37,
|
||||
last_seen_remote_ip_location_lon: -120
|
||||
)
|
||||
|
||||
:ok = Domain.Relays.connect_relay(relay, Ecto.UUID.generate())
|
||||
|
||||
Fixtures.Relays.update_relay(relay,
|
||||
Fixtures.Relays.update_relay(global_relay,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
ref = push(socket, "prepare_connection", %{"resource_id" => resource.id})
|
||||
|
||||
@@ -2924,20 +2908,13 @@ defmodule API.Client.ChannelTest do
|
||||
gateway_group: gateway_group,
|
||||
dns_resource: resource,
|
||||
subject: subject,
|
||||
client: client
|
||||
client: client,
|
||||
global_relay: global_relay,
|
||||
global_relay_token: global_relay_token
|
||||
} do
|
||||
global_relay_group = Fixtures.Relays.create_global_group()
|
||||
:ok = Domain.Relays.connect_relay(global_relay, Ecto.UUID.generate(), global_relay_token.id)
|
||||
|
||||
relay =
|
||||
Fixtures.Relays.create_relay(
|
||||
group: global_relay_group,
|
||||
last_seen_remote_ip_location_lat: 37,
|
||||
last_seen_remote_ip_location_lon: -120
|
||||
)
|
||||
|
||||
:ok = Domain.Relays.connect_relay(relay, Ecto.UUID.generate())
|
||||
|
||||
Fixtures.Relays.update_relay(relay,
|
||||
Fixtures.Relays.update_relay(global_relay,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
)
|
||||
|
||||
@@ -2953,8 +2930,10 @@ defmodule API.Client.ChannelTest do
|
||||
user_agent: "Linux/24.04 connlib/1.0.412"
|
||||
)
|
||||
)
|
||||
|> Repo.preload(:group)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
{:ok, _reply, socket} =
|
||||
API.Client.Socket
|
||||
@@ -2978,8 +2957,10 @@ defmodule API.Client.ChannelTest do
|
||||
user_agent: "Linux/24.04 connlib/1.1.11"
|
||||
)
|
||||
)
|
||||
|> Repo.preload(:group)
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
ref = push(socket, "prepare_connection", %{"resource_id" => resource.id})
|
||||
|
||||
@@ -3015,8 +2996,9 @@ defmodule API.Client.ChannelTest do
|
||||
dns_resource: resource,
|
||||
socket: socket
|
||||
} do
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account) |> Repo.preload(:group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
attrs = %{
|
||||
"resource_id" => resource.id,
|
||||
@@ -3063,7 +3045,9 @@ defmodule API.Client.ChannelTest do
|
||||
"payload" => "DNS_Q"
|
||||
}
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
:ok = PubSub.Account.subscribe(account.id)
|
||||
|
||||
send(socket.channel_pid, {:created, resource})
|
||||
@@ -3083,8 +3067,9 @@ defmodule API.Client.ChannelTest do
|
||||
} do
|
||||
resource = Fixtures.Resources.create_resource(account: account)
|
||||
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account) |> Repo.preload(:group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
attrs = %{
|
||||
"resource_id" => resource.id,
|
||||
@@ -3112,6 +3097,7 @@ defmodule API.Client.ChannelTest do
|
||||
end
|
||||
|
||||
test "broadcasts allow_access to the gateways and then returns connect message", %{
|
||||
account: account,
|
||||
dns_resource: resource,
|
||||
dns_resource_policy: policy,
|
||||
membership: membership,
|
||||
@@ -3123,7 +3109,9 @@ defmodule API.Client.ChannelTest do
|
||||
resource_id = resource.id
|
||||
client_id = client.id
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
:ok = PubSub.Account.subscribe(resource.account_id)
|
||||
|
||||
send(socket.channel_pid, %Changes.Change{
|
||||
@@ -3204,7 +3192,9 @@ defmodule API.Client.ChannelTest do
|
||||
})
|
||||
|> subscribe_and_join(API.Client.Channel, "client")
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
Phoenix.PubSub.subscribe(PubSub, Domain.Tokens.socket_id(gateway_group_token))
|
||||
|
||||
:ok = PubSub.Account.subscribe(account.id)
|
||||
@@ -3255,8 +3245,9 @@ defmodule API.Client.ChannelTest do
|
||||
dns_resource: resource,
|
||||
socket: socket
|
||||
} do
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account) |> Repo.preload(:group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
attrs = %{
|
||||
"resource_id" => resource.id,
|
||||
@@ -3275,8 +3266,9 @@ defmodule API.Client.ChannelTest do
|
||||
} do
|
||||
resource = Fixtures.Resources.create_resource(account: account)
|
||||
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account) |> Repo.preload(:group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
attrs = %{
|
||||
"resource_id" => resource.id,
|
||||
@@ -3325,7 +3317,9 @@ defmodule API.Client.ChannelTest do
|
||||
"client_preshared_key" => "PSK"
|
||||
}
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
|
||||
:ok = PubSub.Account.subscribe(account.id)
|
||||
|
||||
@@ -3371,6 +3365,7 @@ defmodule API.Client.ChannelTest do
|
||||
end
|
||||
|
||||
test "broadcasts request_connection to the gateways and then returns connect message", %{
|
||||
account: account,
|
||||
dns_resource: resource,
|
||||
gateway_group_token: gateway_group_token,
|
||||
gateway: gateway,
|
||||
@@ -3381,7 +3376,9 @@ defmodule API.Client.ChannelTest do
|
||||
resource_id = resource.id
|
||||
client_id = client.id
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
PubSub.subscribe(Domain.Tokens.socket_id(gateway_group_token))
|
||||
|
||||
:ok = PubSub.Account.subscribe(resource.account_id)
|
||||
@@ -3447,7 +3444,9 @@ defmodule API.Client.ChannelTest do
|
||||
})
|
||||
|> subscribe_and_join(API.Client.Channel, "client")
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
Phoenix.PubSub.subscribe(PubSub, Domain.Tokens.socket_id(gateway_group_token))
|
||||
|
||||
:ok = PubSub.Account.subscribe(account.id)
|
||||
@@ -3481,6 +3480,7 @@ defmodule API.Client.ChannelTest do
|
||||
end
|
||||
|
||||
test "broadcasts :ice_candidates message to all gateways", %{
|
||||
account: account,
|
||||
client: client,
|
||||
gateway_group_token: gateway_group_token,
|
||||
gateway: gateway,
|
||||
@@ -3493,7 +3493,9 @@ defmodule API.Client.ChannelTest do
|
||||
"gateway_ids" => [gateway.id]
|
||||
}
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
PubSub.subscribe(Domain.Tokens.socket_id(gateway_group_token))
|
||||
|
||||
:ok = PubSub.Account.subscribe(client.account_id)
|
||||
@@ -3523,6 +3525,7 @@ defmodule API.Client.ChannelTest do
|
||||
end
|
||||
|
||||
test "broadcasts :invalidate_ice_candidates message to all gateways", %{
|
||||
account: account,
|
||||
client: client,
|
||||
gateway_group_token: gateway_group_token,
|
||||
gateway: gateway,
|
||||
@@ -3535,7 +3538,9 @@ defmodule API.Client.ChannelTest do
|
||||
"gateway_ids" => [gateway.id]
|
||||
}
|
||||
|
||||
:ok = Gateways.Presence.connect(gateway)
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
:ok = Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
:ok = PubSub.subscribe(Domain.Tokens.socket_id(gateway_group_token))
|
||||
:ok = PubSub.Account.subscribe(client.account_id)
|
||||
|
||||
|
||||
@@ -281,8 +281,7 @@ defmodule API.ActorControllerTest do
|
||||
}
|
||||
}
|
||||
|
||||
assert actor = Repo.get(Actor, actor.id)
|
||||
assert actor.deleted_at
|
||||
refute Repo.get(Actor, actor.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -219,8 +219,7 @@ defmodule API.ActorGroupControllerTest do
|
||||
}
|
||||
}
|
||||
|
||||
assert actor_group = Repo.get(Group, actor_group.id)
|
||||
assert actor_group.deleted_at
|
||||
refute Repo.get(Group, actor_group.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -278,7 +278,7 @@ defmodule API.ClientControllerTest do
|
||||
client.last_seen_remote_ip_location_region,
|
||||
"last_seen_user_agent" => client.last_seen_user_agent,
|
||||
"last_seen_version" => client.last_seen_version,
|
||||
"online" => nil,
|
||||
"online" => false,
|
||||
"updated_at" => client.updated_at && DateTime.to_iso8601(client.updated_at),
|
||||
"verified_at" => client.verified_at && DateTime.to_iso8601(client.verified_at),
|
||||
"verified_by" => client.verified_by,
|
||||
@@ -286,8 +286,7 @@ defmodule API.ClientControllerTest do
|
||||
}
|
||||
}
|
||||
|
||||
assert client = Repo.get(Client, client.id)
|
||||
assert client.deleted_at
|
||||
refute Repo.get(Client, client.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -170,8 +170,7 @@ defmodule API.GatewayControllerTest do
|
||||
}
|
||||
}
|
||||
|
||||
assert gateway = Repo.get(Gateway, gateway.id)
|
||||
assert gateway.deleted_at
|
||||
refute Repo.get(Gateway, gateway.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -219,8 +219,7 @@ defmodule API.GatewayGroupControllerTest do
|
||||
}
|
||||
}
|
||||
|
||||
assert gateway_group = Repo.get(Group, gateway_group.id)
|
||||
assert gateway_group.deleted_at
|
||||
refute Repo.get(Group, gateway_group.id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -267,8 +266,7 @@ defmodule API.GatewayGroupControllerTest do
|
||||
|
||||
assert %{"data" => %{"id" => _id}} = json_response(conn, 200)
|
||||
|
||||
assert token = Repo.get(Token, token.id)
|
||||
assert token.deleted_at
|
||||
refute Repo.get(Token, token.id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -296,12 +294,10 @@ defmodule API.GatewayGroupControllerTest do
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> delete("/gateway_groups/#{gateway_group.id}/tokens")
|
||||
|
||||
assert %{"data" => [%{"id" => _id1}, %{"id" => _id2}, %{"id" => _id3}]} =
|
||||
json_response(conn, 200)
|
||||
assert %{"data" => %{"deleted_count" => 3}} = json_response(conn, 200)
|
||||
|
||||
Enum.map(tokens, fn token ->
|
||||
assert token = Repo.get(Token, token.id)
|
||||
assert token.deleted_at
|
||||
refute Repo.get(Token, token.id)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -306,8 +306,7 @@ defmodule API.IdentityControllerTest do
|
||||
}
|
||||
}
|
||||
|
||||
assert identity = Repo.get(Identity, identity.id)
|
||||
assert identity.deleted_at
|
||||
refute Repo.get(Identity, identity.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -139,8 +139,38 @@ defmodule API.IdentityProviderControllerTest do
|
||||
}
|
||||
}
|
||||
|
||||
assert identity_provider = Repo.get(Provider, identity_provider.id)
|
||||
assert identity_provider.deleted_at
|
||||
refute Repo.get(Provider, identity_provider.id)
|
||||
end
|
||||
|
||||
test "returns not found on invalid ID", %{conn: conn, account: account, actor: actor} do
|
||||
{_identity_provider, _bypass} =
|
||||
Fixtures.Auth.start_and_create_openid_connect_provider(%{account: account})
|
||||
|
||||
invalid_id = Ecto.UUID.generate()
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> authorize_conn(actor)
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> delete("/identity_providers/#{invalid_id}")
|
||||
|
||||
assert json_response(conn, 404) == %{"error" => %{"reason" => "Not Found"}}
|
||||
end
|
||||
|
||||
test "returns not found on ID belonging to another account", %{conn: conn, actor: actor} do
|
||||
other_account = Fixtures.Accounts.create_account()
|
||||
|
||||
{identity_provider, _bypass} =
|
||||
Fixtures.Auth.start_and_create_openid_connect_provider(%{account: other_account})
|
||||
|
||||
conn =
|
||||
conn
|
||||
|> authorize_conn(actor)
|
||||
|> put_req_header("content-type", "application/json")
|
||||
|> delete("/identity_providers/#{identity_provider.id}")
|
||||
|
||||
assert json_response(conn, 404) == %{"error" => %{"reason" => "Not Found"}}
|
||||
assert Repo.get(Domain.Auth.Provider, identity_provider.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -231,8 +231,7 @@ defmodule API.PolicyControllerTest do
|
||||
}
|
||||
}
|
||||
|
||||
assert policy = Repo.get(Policy, policy.id)
|
||||
assert policy.deleted_at
|
||||
refute Repo.get(Policy, policy.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -270,8 +270,7 @@ defmodule API.ResourceControllerTest do
|
||||
}
|
||||
}
|
||||
|
||||
assert resource = Repo.get(Resource, resource.id)
|
||||
assert resource.deleted_at
|
||||
refute Repo.get(Resource, resource.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -364,7 +364,9 @@ defmodule API.Gateway.ChannelTest do
|
||||
client_payload = "RTC_SD_or_DNS_Q"
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret)
|
||||
relay = Repo.preload(relay, :group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret, relay_token.id)
|
||||
|
||||
send(
|
||||
socket.channel_pid,
|
||||
@@ -428,7 +430,9 @@ defmodule API.Gateway.ChannelTest do
|
||||
client_payload = "RTC_SD_or_DNS_Q"
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret)
|
||||
relay = Repo.preload(relay, :group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret, relay_token.id)
|
||||
|
||||
send(
|
||||
socket.channel_pid,
|
||||
@@ -570,7 +574,9 @@ defmodule API.Gateway.ChannelTest do
|
||||
client_payload = "RTC_SD_or_DNS_Q"
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret)
|
||||
relay = Repo.preload(relay, :group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret, relay_token.id)
|
||||
|
||||
flow =
|
||||
Fixtures.Flows.create_flow(
|
||||
@@ -634,7 +640,9 @@ defmodule API.Gateway.ChannelTest do
|
||||
client_payload = "RTC_SD_or_DNS_Q"
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret)
|
||||
relay = Repo.preload(relay, :group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret, relay_token.id)
|
||||
|
||||
flow =
|
||||
Fixtures.Flows.create_flow(
|
||||
@@ -796,7 +804,9 @@ defmodule API.Gateway.ChannelTest do
|
||||
expires_at = DateTime.utc_now() |> DateTime.add(30, :second)
|
||||
client_payload = "RTC_SD_or_DNS_Q"
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret)
|
||||
relay = Repo.preload(relay, :group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret, relay_token.id)
|
||||
|
||||
send(
|
||||
socket.channel_pid,
|
||||
@@ -1162,12 +1172,17 @@ defmodule API.Gateway.ChannelTest do
|
||||
}
|
||||
end
|
||||
|
||||
test "subscribes for relays presence", %{gateway: gateway, gateway_group: gateway_group} do
|
||||
test "subscribes for relays presence", %{
|
||||
gateway: gateway,
|
||||
gateway_group: gateway_group,
|
||||
token: token
|
||||
} do
|
||||
relay_group = Fixtures.Relays.create_global_group()
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
|
||||
relay1 = Fixtures.Relays.create_relay(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret, relay_token.id)
|
||||
|
||||
Fixtures.Relays.update_relay(relay1,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second),
|
||||
@@ -1176,7 +1191,7 @@ defmodule API.Gateway.ChannelTest do
|
||||
)
|
||||
|
||||
relay2 = Fixtures.Relays.create_relay(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay2, stamp_secret)
|
||||
:ok = Domain.Relays.connect_relay(relay2, stamp_secret, relay_token.id)
|
||||
|
||||
Fixtures.Relays.update_relay(relay2,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-100, :second),
|
||||
@@ -1186,6 +1201,7 @@ defmodule API.Gateway.ChannelTest do
|
||||
|
||||
API.Gateway.Socket
|
||||
|> socket("gateway:#{gateway.id}", %{
|
||||
token_id: token.id,
|
||||
gateway: gateway,
|
||||
gateway_group: gateway_group,
|
||||
opentelemetry_ctx: OpenTelemetry.Ctx.new(),
|
||||
@@ -1223,7 +1239,8 @@ defmodule API.Gateway.ChannelTest do
|
||||
|
||||
test "subscribes for account relays presence if there were no relays online", %{
|
||||
gateway: gateway,
|
||||
gateway_group: gateway_group
|
||||
gateway_group: gateway_group,
|
||||
token: token
|
||||
} do
|
||||
relay_group = Fixtures.Relays.create_global_group()
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
@@ -1238,6 +1255,7 @@ defmodule API.Gateway.ChannelTest do
|
||||
|
||||
API.Gateway.Socket
|
||||
|> socket("gateway:#{gateway.id}", %{
|
||||
token_id: token.id,
|
||||
gateway: gateway,
|
||||
gateway_group: gateway_group,
|
||||
opentelemetry_ctx: OpenTelemetry.Ctx.new(),
|
||||
@@ -1247,7 +1265,8 @@ defmodule API.Gateway.ChannelTest do
|
||||
|
||||
assert_push "init", %{relays: []}
|
||||
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret, relay_token.id)
|
||||
|
||||
assert_push "relays_presence",
|
||||
%{
|
||||
@@ -1273,7 +1292,7 @@ defmodule API.Gateway.ChannelTest do
|
||||
last_seen_remote_ip_location_lon: -120.0
|
||||
)
|
||||
|
||||
:ok = Domain.Relays.connect_relay(other_relay, stamp_secret)
|
||||
:ok = Domain.Relays.connect_relay(other_relay, stamp_secret, relay_token.id)
|
||||
other_relay_id = other_relay.id
|
||||
|
||||
refute_push "relays_presence",
|
||||
@@ -1346,7 +1365,9 @@ defmodule API.Gateway.ChannelTest do
|
||||
client_payload = "RTC_SD"
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret)
|
||||
relay = Repo.preload(relay, :group)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay.group)
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret, relay_token.id)
|
||||
|
||||
send(
|
||||
socket.channel_pid,
|
||||
@@ -1410,7 +1431,9 @@ defmodule API.Gateway.ChannelTest do
|
||||
preshared_key = "PSK"
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret)
|
||||
relay = Repo.preload(relay, :group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret, relay_token.id)
|
||||
|
||||
flow =
|
||||
Fixtures.Flows.create_flow(
|
||||
@@ -1696,7 +1719,9 @@ defmodule API.Gateway.ChannelTest do
|
||||
payload = "RTC_SD"
|
||||
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret)
|
||||
relay = Repo.preload(relay, :group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
:ok = Domain.Relays.connect_relay(relay, stamp_secret, relay_token.id)
|
||||
|
||||
send(
|
||||
socket.channel_pid,
|
||||
@@ -1775,7 +1800,8 @@ defmodule API.Gateway.ChannelTest do
|
||||
client: client,
|
||||
gateway: gateway,
|
||||
subject: subject,
|
||||
socket: socket
|
||||
socket: socket,
|
||||
account: account
|
||||
} do
|
||||
candidates = ["foo", "bar"]
|
||||
|
||||
@@ -1784,7 +1810,17 @@ defmodule API.Gateway.ChannelTest do
|
||||
"client_ids" => [client.id]
|
||||
}
|
||||
|
||||
:ok = Domain.Clients.Presence.connect(client)
|
||||
client_actor = Fixtures.Actors.create_actor(account: account, type: :service_account)
|
||||
client_identity = Fixtures.Auth.create_identity(account: account, actor: client_actor)
|
||||
|
||||
client_token =
|
||||
Fixtures.Tokens.create_client_token(
|
||||
account: account,
|
||||
actor: client_actor,
|
||||
identity: client_identity
|
||||
)
|
||||
|
||||
:ok = Domain.Clients.Presence.connect(client, client_token.id)
|
||||
PubSub.subscribe(Domain.Tokens.socket_id(subject.token_id))
|
||||
:ok = PubSub.Account.subscribe(gateway.account_id)
|
||||
|
||||
@@ -1818,7 +1854,8 @@ defmodule API.Gateway.ChannelTest do
|
||||
client: client,
|
||||
gateway: gateway,
|
||||
subject: subject,
|
||||
socket: socket
|
||||
socket: socket,
|
||||
account: account
|
||||
} do
|
||||
candidates = ["foo", "bar"]
|
||||
|
||||
@@ -1828,7 +1865,17 @@ defmodule API.Gateway.ChannelTest do
|
||||
}
|
||||
|
||||
:ok = PubSub.Account.subscribe(gateway.account_id)
|
||||
:ok = Domain.Clients.Presence.connect(client)
|
||||
client_actor = Fixtures.Actors.create_actor(account: account, type: :service_account)
|
||||
client_identity = Fixtures.Auth.create_identity(account: account, actor: client_actor)
|
||||
|
||||
client_token =
|
||||
Fixtures.Tokens.create_client_token(
|
||||
account: account,
|
||||
actor: client_actor,
|
||||
identity: client_identity
|
||||
)
|
||||
|
||||
:ok = Domain.Clients.Presence.connect(client, client_token.id)
|
||||
PubSub.subscribe(Domain.Tokens.socket_id(subject.token_id))
|
||||
|
||||
push(socket, "broadcast_invalidated_ice_candidates", attrs)
|
||||
@@ -1848,7 +1895,8 @@ defmodule API.Gateway.ChannelTest do
|
||||
|
||||
relay1 = Fixtures.Relays.create_relay(group: relay_group)
|
||||
stamp_secret1 = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1, relay_token.id)
|
||||
|
||||
assert_push "relays_presence",
|
||||
%{
|
||||
@@ -1866,7 +1914,7 @@ defmodule API.Gateway.ChannelTest do
|
||||
Process.sleep(1)
|
||||
|
||||
# Reconnect with the same stamp secret
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1, relay_token.id)
|
||||
|
||||
# Should not receive any disconnect
|
||||
relay_id = relay1.id
|
||||
@@ -1884,7 +1932,8 @@ defmodule API.Gateway.ChannelTest do
|
||||
|
||||
relay1 = Fixtures.Relays.create_relay(group: relay_group)
|
||||
stamp_secret1 = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1, relay_token.id)
|
||||
|
||||
assert_push "relays_presence",
|
||||
%{
|
||||
@@ -1903,7 +1952,7 @@ defmodule API.Gateway.ChannelTest do
|
||||
|
||||
# Reconnect with a different stamp secret
|
||||
stamp_secret2 = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret2)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret2, relay_token.id)
|
||||
|
||||
# Should receive disconnect "immediately"
|
||||
assert_push "relays_presence",
|
||||
@@ -1923,7 +1972,8 @@ defmodule API.Gateway.ChannelTest do
|
||||
|
||||
relay1 = Fixtures.Relays.create_relay(group: relay_group)
|
||||
stamp_secret1 = Ecto.UUID.generate()
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay_group)
|
||||
:ok = Domain.Relays.connect_relay(relay1, stamp_secret1, relay_token.id)
|
||||
|
||||
assert_push "relays_presence",
|
||||
%{
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
defmodule API.Relay.ChannelTest do
|
||||
use API.ChannelCase, async: true
|
||||
alias Domain.Relays
|
||||
alias Domain.{Relays, Repo}
|
||||
|
||||
setup do
|
||||
relay = Fixtures.Relays.create_relay()
|
||||
relay = Fixtures.Relays.create_relay() |> Repo.preload([:group, :account])
|
||||
token = Fixtures.Relays.create_token(group: relay.group, account: relay.account)
|
||||
|
||||
stamp_secret = Domain.Crypto.random_token()
|
||||
|
||||
{:ok, _, socket} =
|
||||
API.Relay.Socket
|
||||
|> socket("relay:#{relay.id}", %{
|
||||
token_id: token.id,
|
||||
relay: relay,
|
||||
opentelemetry_ctx: OpenTelemetry.Ctx.new(),
|
||||
opentelemetry_span_ctx: OpenTelemetry.Tracer.start_span("test")
|
||||
@@ -30,12 +32,14 @@ defmodule API.Relay.ChannelTest do
|
||||
test "tracks presence after join of an global relay" do
|
||||
group = Fixtures.Relays.create_global_group()
|
||||
relay = Fixtures.Relays.create_relay(group: group)
|
||||
token = Fixtures.Relays.create_global_token(group: group)
|
||||
|
||||
stamp_secret = Domain.Crypto.random_token()
|
||||
|
||||
{:ok, _, _socket} =
|
||||
API.Relay.Socket
|
||||
|> socket("relay:#{relay.id}", %{
|
||||
token_id: token.id,
|
||||
relay: relay,
|
||||
opentelemetry_ctx: OpenTelemetry.Ctx.new(),
|
||||
opentelemetry_span_ctx: OpenTelemetry.Tracer.start_span("test")
|
||||
|
||||
@@ -110,6 +110,7 @@ defmodule Domain.Accounts do
|
||||
Map.fetch!(account.features || %Features{}, feature) || false
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Update after `deleted_at` is removed from DB
|
||||
def account_active?(%{deleted_at: nil, disabled_at: nil}), do: true
|
||||
def account_active?(_account), do: false
|
||||
|
||||
|
||||
@@ -25,30 +25,40 @@ defmodule Domain.Accounts.Account do
|
||||
|
||||
# We mention all schemas here to leverage Ecto compile-time reference checks,
|
||||
# because later we will have to shard data by account_id.
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :actors, Domain.Actors.Actor, where: [deleted_at: nil]
|
||||
has_many :actor_group_memberships, Domain.Actors.Membership, where: [deleted_at: nil]
|
||||
has_many :actor_groups, Domain.Actors.Group, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :auth_providers, Domain.Auth.Provider, where: [deleted_at: nil]
|
||||
has_many :auth_identities, Domain.Auth.Identity, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :network_addresses, Domain.Network.Address, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :policies, Domain.Policies.Policy, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :flows, Domain.Flows.Flow, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :resources, Domain.Resources.Resource, where: [deleted_at: nil]
|
||||
has_many :resource_connections, Domain.Resources.Connection, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :clients, Domain.Clients.Client, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :gateways, Domain.Gateways.Gateway, where: [deleted_at: nil]
|
||||
has_many :gateway_groups, Domain.Gateways.Group, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :relays, Domain.Relays.Relay, where: [deleted_at: nil]
|
||||
has_many :relay_groups, Domain.Relays.Group, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :tokens, Domain.Tokens.Token, where: [deleted_at: nil]
|
||||
|
||||
field :warning, :string
|
||||
@@ -58,6 +68,7 @@ defmodule Domain.Accounts.Account do
|
||||
field :disabled_reason, :string
|
||||
field :disabled_at, :utc_datetime_usec
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Accounts.Account.Query do
|
||||
from(accounts in Domain.Accounts.Account, as: :accounts)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def not_deleted(queryable \\ all()) do
|
||||
where(queryable, [accounts: accounts], is_nil(accounts.deleted_at))
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Actors do
|
||||
alias Domain.{Accounts, Auth, Tokens, Clients, Policies, Billing}
|
||||
alias Domain.Actors.{Authorizer, Actor, Group}
|
||||
require Ecto.Query
|
||||
require Logger
|
||||
|
||||
# Groups
|
||||
|
||||
@@ -246,13 +247,24 @@ defmodule Domain.Actors do
|
||||
end
|
||||
|
||||
def delete_group(%Group{provider_id: nil} = group, %Auth.Subject{} = subject) do
|
||||
with :ok <- Group.Authorizer.ensure_has_access_to(group, subject) do
|
||||
Repo.delete(group)
|
||||
end
|
||||
end
|
||||
|
||||
def delete_group(%Group{}, %Auth.Subject{}) do
|
||||
{:error, :synced_group}
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone
|
||||
def soft_delete_group(%Group{provider_id: nil} = group, %Auth.Subject{} = subject) do
|
||||
queryable =
|
||||
Group.Query.not_deleted()
|
||||
|> Group.Query.by_id(group.id)
|
||||
|
||||
case delete_groups(queryable, subject) do
|
||||
case soft_delete_groups(queryable, subject) do
|
||||
{:ok, [group]} ->
|
||||
{:ok, _policies} = Policies.delete_policies_for(group, subject)
|
||||
{:ok, _policies} = Policies.soft_delete_policies_for(group, subject)
|
||||
|
||||
# TODO: Hard delete
|
||||
# Consider using a trigger or transaction to handle the side effects of soft-deletions to ensure consistency
|
||||
@@ -271,11 +283,13 @@ defmodule Domain.Actors do
|
||||
end
|
||||
end
|
||||
|
||||
def delete_group(%Group{}, %Auth.Subject{}) do
|
||||
# TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone
|
||||
def soft_delete_group(%Group{}, %Auth.Subject{}) do
|
||||
{:error, :synced_group}
|
||||
end
|
||||
|
||||
def delete_groups_for(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do
|
||||
# TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone
|
||||
def soft_delete_groups_for(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do
|
||||
queryable =
|
||||
Group.Query.not_deleted()
|
||||
|> Group.Query.by_provider_id(provider.id)
|
||||
@@ -287,13 +301,14 @@ defmodule Domain.Actors do
|
||||
Membership.Query.by_group_provider_id(provider.id)
|
||||
|> Repo.delete_all()
|
||||
|
||||
with {:ok, groups} <- delete_groups(queryable, subject) do
|
||||
{:ok, _policies} = Policies.delete_policies_for(provider, subject)
|
||||
with {:ok, groups} <- soft_delete_groups(queryable, subject) do
|
||||
{:ok, _policies} = Policies.soft_delete_policies_for(provider, subject)
|
||||
{:ok, groups}
|
||||
end
|
||||
end
|
||||
|
||||
defp delete_groups(queryable, subject) do
|
||||
# TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone
|
||||
defp soft_delete_groups(queryable, subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do
|
||||
{_count, groups} =
|
||||
queryable
|
||||
@@ -307,7 +322,8 @@ defmodule Domain.Actors do
|
||||
|
||||
@doc false
|
||||
# used in sync workers
|
||||
def delete_groups(queryable) do
|
||||
# TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone
|
||||
def soft_delete_groups(queryable) do
|
||||
{_count, groups} =
|
||||
queryable
|
||||
|> Group.Query.delete()
|
||||
@@ -315,7 +331,7 @@ defmodule Domain.Actors do
|
||||
|
||||
:ok =
|
||||
Enum.each(groups, fn group ->
|
||||
{:ok, _policies} = Domain.Policies.delete_policies_for(group)
|
||||
{:ok, _policies} = Domain.Policies.soft_delete_policies_for(group)
|
||||
end)
|
||||
|
||||
# TODO: Hard delete
|
||||
@@ -334,10 +350,11 @@ defmodule Domain.Actors do
|
||||
def group_managed?(%Group{}), do: false
|
||||
|
||||
def group_editable?(%Group{} = group),
|
||||
do: not group_deleted?(group) and not group_synced?(group) and not group_managed?(group)
|
||||
do: not group_soft_deleted?(group) and not group_synced?(group) and not group_managed?(group)
|
||||
|
||||
def group_deleted?(%Group{deleted_at: nil}), do: false
|
||||
def group_deleted?(%Group{}), do: true
|
||||
# TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone
|
||||
def group_soft_deleted?(%Group{deleted_at: nil}), do: false
|
||||
def group_soft_deleted?(%Group{}), do: true
|
||||
|
||||
# Actors
|
||||
|
||||
@@ -567,7 +584,7 @@ defmodule Domain.Actors do
|
||||
|> Repo.fetch_and_update(Actor.Query,
|
||||
with: fn actor ->
|
||||
if actor.type != :account_admin_user or other_enabled_admins_exist?(actor) do
|
||||
{:ok, _tokens} = Tokens.delete_tokens_for(actor, subject)
|
||||
{:ok, _num_tokens} = Tokens.delete_tokens_for(actor, subject)
|
||||
Actor.Changeset.disable_actor(actor)
|
||||
else
|
||||
:cant_disable_the_last_admin
|
||||
@@ -587,6 +604,20 @@ defmodule Domain.Actors do
|
||||
end
|
||||
|
||||
def delete_actor(%Actor{} = actor, %Auth.Subject{} = subject) do
|
||||
with :ok <- Authorizer.ensure_has_access_to(actor, subject),
|
||||
true <- actor.type != :account_admin_user or other_enabled_admins_exist?(actor) do
|
||||
Repo.delete(actor)
|
||||
else
|
||||
false ->
|
||||
{:error, :cant_delete_the_last_admin}
|
||||
|
||||
other ->
|
||||
other
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove this after `deleted_at` column is removed from DB
|
||||
def soft_delete_actor(%Actor{} = actor, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_actors_permission()) do
|
||||
Actor.Query.not_deleted()
|
||||
|> Actor.Query.by_id(actor.id)
|
||||
@@ -594,7 +625,7 @@ defmodule Domain.Actors do
|
||||
|> Repo.fetch_and_update(Actor.Query,
|
||||
with: fn actor ->
|
||||
if actor.type != :account_admin_user or other_enabled_admins_exist?(actor) do
|
||||
:ok = Auth.delete_identities_for(actor, subject)
|
||||
:ok = Auth.soft_delete_identities_for(actor, subject)
|
||||
:ok = Clients.delete_clients_for(actor, subject)
|
||||
|
||||
# TODO: Hard delete
|
||||
@@ -633,12 +664,14 @@ defmodule Domain.Actors do
|
||||
def actor_synced?(%Actor{last_synced_at: nil}), do: false
|
||||
def actor_synced?(%Actor{}), do: true
|
||||
|
||||
# TODO: HARD-DELETE - Remove this once the `deleted_at` field in the DB is gone
|
||||
def actor_deleted?(%Actor{deleted_at: nil}), do: false
|
||||
def actor_deleted?(%Actor{}), do: true
|
||||
|
||||
def actor_disabled?(%Actor{disabled_at: nil}), do: false
|
||||
def actor_disabled?(%Actor{}), do: true
|
||||
|
||||
# TODO: HARD-DELETE - Update this once the `deleted_at` field in the DB is gone
|
||||
def actor_active?(%Actor{disabled_at: nil, deleted_at: nil}), do: true
|
||||
def actor_active?(%Actor{}), do: false
|
||||
|
||||
|
||||
@@ -7,12 +7,15 @@ defmodule Domain.Actors.Actor do
|
||||
|
||||
field :name, :string
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from DB
|
||||
has_many :identities, Domain.Auth.Identity, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from DB
|
||||
has_many :clients, Domain.Clients.Client,
|
||||
where: [deleted_at: nil],
|
||||
preload_order: [desc: :last_seen_at]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from DB
|
||||
has_many :tokens, Domain.Tokens.Token, where: [deleted_at: nil]
|
||||
|
||||
has_many :memberships, Domain.Actors.Membership, on_replace: :delete
|
||||
@@ -25,6 +28,8 @@ defmodule Domain.Actors.Actor do
|
||||
field :last_seen_at, :utc_datetime_usec, virtual: true
|
||||
field :last_synced_at, :utc_datetime_usec
|
||||
field :disabled_at, :utc_datetime_usec
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@@ -81,6 +81,7 @@ defmodule Domain.Actors.Actor.Changeset do
|
||||
|> put_change(:disabled_at, nil)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def delete_actor(%Actor{} = actor) do
|
||||
actor
|
||||
|> change()
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Actors.Actor.Query do
|
||||
from(actors in Domain.Actors.Actor, as: :actors)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def not_deleted do
|
||||
all()
|
||||
|> where([actors: actors], is_nil(actors.deleted_at))
|
||||
@@ -30,6 +31,7 @@ defmodule Domain.Actors.Actor.Query do
|
||||
where(queryable, [actors: actors], actors.account_id == ^account_id)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB
|
||||
def by_deleted_identity_provider_id(queryable, provider_id) do
|
||||
queryable
|
||||
|> join(:inner, [actors: actors], identities in ^Domain.Auth.Identity.Query.deleted(),
|
||||
@@ -42,6 +44,7 @@ defmodule Domain.Actors.Actor.Query do
|
||||
)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Update after `deleted_at` column is removed in DB
|
||||
def by_stale_for_provider(queryable, provider_id) do
|
||||
subquery =
|
||||
Domain.Auth.Identity.Query.all()
|
||||
@@ -329,6 +332,7 @@ defmodule Domain.Actors.Actor.Query do
|
||||
{queryable, dynamic(exists(subquery))}
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB
|
||||
def filter_deleted(queryable) do
|
||||
{queryable, dynamic([actors: actors], not is_nil(actors.deleted_at))}
|
||||
end
|
||||
|
||||
@@ -30,6 +30,14 @@ defmodule Domain.Actors.Authorizer do
|
||||
[]
|
||||
end
|
||||
|
||||
def ensure_has_access_to(%Actor{} = actor, %Subject{} = subject) do
|
||||
if actor.account_id == subject.account.id do
|
||||
Domain.Auth.ensure_has_permissions(subject, manage_actors_permission())
|
||||
else
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@impl Domain.Auth.Authorizer
|
||||
def for_subject(queryable, %Subject{} = subject) do
|
||||
cond do
|
||||
|
||||
@@ -9,6 +9,7 @@ defmodule Domain.Actors.Group do
|
||||
belongs_to :provider, Domain.Auth.Provider
|
||||
field :provider_identifier, :string
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` column is removed from DB
|
||||
has_many :policies, Domain.Policies.Policy,
|
||||
foreign_key: :actor_group_id,
|
||||
where: [deleted_at: nil]
|
||||
@@ -24,6 +25,7 @@ defmodule Domain.Actors.Group do
|
||||
|
||||
belongs_to :account, Domain.Accounts.Account
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
end
|
||||
|
||||
53
elixir/apps/domain/lib/domain/actors/group/authorizer.ex
Normal file
53
elixir/apps/domain/lib/domain/actors/group/authorizer.ex
Normal file
@@ -0,0 +1,53 @@
|
||||
defmodule Domain.Actors.Group.Authorizer do
|
||||
use Domain.Auth.Authorizer
|
||||
alias Domain.Actors.{Actor, Group}
|
||||
|
||||
def manage_actor_groups_permission, do: build(Group, :manage)
|
||||
|
||||
@impl Domain.Auth.Authorizer
|
||||
def list_permissions_for_role(:account_admin_user) do
|
||||
[
|
||||
manage_actor_groups_permission()
|
||||
]
|
||||
end
|
||||
|
||||
def list_permissions_for_role(:api_client) do
|
||||
[
|
||||
manage_actor_groups_permission()
|
||||
]
|
||||
end
|
||||
|
||||
def list_permissions_for_role(:account_user) do
|
||||
[]
|
||||
end
|
||||
|
||||
def list_permissions_for_role(_role) do
|
||||
[]
|
||||
end
|
||||
|
||||
def ensure_has_access_to(%Group{} = group, %Subject{} = subject) do
|
||||
if group.account_id == subject.account.id do
|
||||
Domain.Auth.ensure_has_permissions(subject, manage_actor_groups_permission())
|
||||
else
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@impl Domain.Auth.Authorizer
|
||||
def for_subject(queryable, %Subject{} = subject) do
|
||||
cond do
|
||||
has_permission?(subject, manage_actor_groups_permission()) ->
|
||||
by_account_id(queryable, subject.account.id)
|
||||
end
|
||||
end
|
||||
|
||||
defp by_account_id(queryable, account_id) do
|
||||
cond do
|
||||
Ecto.Query.has_named_binding?(queryable, :groups) ->
|
||||
Group.Query.by_account_id(queryable, account_id)
|
||||
|
||||
Ecto.Query.has_named_binding?(queryable, :actors) ->
|
||||
Actor.Query.by_account_id(queryable, account_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -11,6 +11,7 @@ defmodule Domain.Actors.Group.Changeset do
|
||||
"WHERE provider_id IS NOT NULL AND provider_identifier IS NOT NULL"}
|
||||
end
|
||||
|
||||
# TODO: Update after `deleted_at` is removed from the DB
|
||||
def upsert_on_conflict, do: {:replace, ~w[name updated_at deleted_at]a}
|
||||
|
||||
def create(%Accounts.Account{} = account, attrs, %Auth.Subject{} = subject) do
|
||||
@@ -35,6 +36,7 @@ defmodule Domain.Actors.Group.Changeset do
|
||||
|> put_subject_trail(:created_by, :system)
|
||||
end
|
||||
|
||||
# TODO: Update after `deleted_at` is removed from the DB
|
||||
def create(%Auth.Provider{} = provider, attrs) do
|
||||
%Actors.Group{memberships: []}
|
||||
|> cast(attrs, ~w[name provider_identifier]a)
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Actors.Group.Query do
|
||||
from(groups in Domain.Actors.Group, as: :groups)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def not_deleted do
|
||||
all()
|
||||
|> where([groups: groups], is_nil(groups.deleted_at))
|
||||
@@ -63,6 +64,7 @@ defmodule Domain.Actors.Group.Query do
|
||||
where(queryable, [groups: groups], groups.provider_identifier == ^provider_identifier)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def delete(queryable) do
|
||||
queryable
|
||||
|> Ecto.Query.select([groups: groups], groups)
|
||||
@@ -141,6 +143,7 @@ defmodule Domain.Actors.Group.Query do
|
||||
)
|
||||
end
|
||||
|
||||
# TODO: Update after `deleted_at` is removed from DB
|
||||
# TODO: IDP Sync
|
||||
# See: https://github.com/firezone/firezone/issues/8750
|
||||
# We use CTE here which should be very performant even for very large inserts and deletions
|
||||
@@ -253,10 +256,12 @@ defmodule Domain.Actors.Group.Query do
|
||||
{queryable, dynamic([groups: groups], groups.provider_id == ^provider_id)}
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def filter_deleted(queryable) do
|
||||
{queryable, dynamic([groups: groups], not is_nil(groups.deleted_at))}
|
||||
end
|
||||
|
||||
# TODO: Update after `deleted_at` is removed from DB
|
||||
def filter_editable(queryable) do
|
||||
{queryable,
|
||||
dynamic(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
defmodule Domain.Actors.Group.Sync do
|
||||
alias Domain.Repo
|
||||
alias Domain.Auth
|
||||
alias Domain.Actors
|
||||
alias Domain.Actors.Group
|
||||
require Logger
|
||||
|
||||
@@ -16,7 +15,7 @@ defmodule Domain.Actors.Group.Sync do
|
||||
with {:ok, groups} <- all_provider_groups(provider),
|
||||
{:ok, {upsert, delete}} <- plan_groups_update(groups, provider_identifiers),
|
||||
:ok <- deletion_circuit_breaker(groups, delete, provider),
|
||||
{:ok, deleted} <- delete_groups(provider, delete),
|
||||
{:ok, _num_deleted} <- delete_groups(provider, delete),
|
||||
{:ok, upserted} <- upsert_groups(provider, attrs_by_provider_identifier, upsert) do
|
||||
group_ids_by_provider_identifier =
|
||||
for group <- groups ++ upserted,
|
||||
@@ -29,7 +28,7 @@ defmodule Domain.Actors.Group.Sync do
|
||||
%{
|
||||
groups: groups,
|
||||
plan: {upsert, delete},
|
||||
deleted: deleted,
|
||||
deleted: delete,
|
||||
upserted: upserted,
|
||||
group_ids_by_provider_identifier: group_ids_by_provider_identifier
|
||||
}}
|
||||
@@ -46,6 +45,7 @@ defmodule Domain.Actors.Group.Sync do
|
||||
{:ok, groups}
|
||||
end
|
||||
|
||||
# TODO: Update after `deleted_at` is removed from DB
|
||||
defp plan_groups_update(groups, provider_identifiers) do
|
||||
identifiers_set = MapSet.new(provider_identifiers)
|
||||
|
||||
@@ -108,11 +108,14 @@ defmodule Domain.Actors.Group.Sync do
|
||||
end
|
||||
|
||||
defp delete_groups(provider, provider_identifiers_to_delete) do
|
||||
Group.Query.not_deleted()
|
||||
|> Group.Query.by_account_id(provider.account_id)
|
||||
|> Group.Query.by_provider_id(provider.id)
|
||||
|> Group.Query.by_provider_identifier({:in, provider_identifiers_to_delete})
|
||||
|> Actors.delete_groups()
|
||||
{num_deleted, _} =
|
||||
Group.Query.all()
|
||||
|> Group.Query.by_account_id(provider.account_id)
|
||||
|> Group.Query.by_provider_id(provider.id)
|
||||
|> Group.Query.by_provider_identifier({:in, provider_identifiers_to_delete})
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
|
||||
defp upsert_groups(provider, attrs_by_provider_identifier, provider_identifiers_to_upsert) do
|
||||
|
||||
@@ -70,6 +70,7 @@ defmodule Domain.Auth do
|
||||
alias Domain.Auth.{Authorizer, Subject, Context, Permission, Roles, Role}
|
||||
alias Domain.Auth.{Adapters, Provider}
|
||||
alias Domain.Auth.Identity
|
||||
require Logger
|
||||
|
||||
# This session duration is used when IdP doesn't return the token expiration date,
|
||||
# or no IdP is used (eg. sign in via email or userpass).
|
||||
@@ -252,7 +253,7 @@ defmodule Domain.Auth do
|
||||
def disable_provider(%Provider{} = provider, %Subject{} = subject) do
|
||||
mutate_provider(provider, subject, fn provider ->
|
||||
if other_active_providers_exist?(provider) do
|
||||
{:ok, _tokens} = Tokens.delete_tokens_for(provider, subject)
|
||||
{:ok, _num_tokens} = Tokens.delete_tokens_for(provider, subject)
|
||||
Provider.Changeset.disable_provider(provider)
|
||||
else
|
||||
:cant_disable_the_last_provider
|
||||
@@ -296,13 +297,30 @@ defmodule Domain.Auth do
|
||||
mutate_provider(provider, subject, &Provider.Changeset.enable_provider/1)
|
||||
end
|
||||
|
||||
def delete_provider_by_id(provider_id, %Subject{} = subject) do
|
||||
case fetch_provider_by_id(provider_id, subject) do
|
||||
{:ok, provider} ->
|
||||
delete_provider(provider, subject)
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
def delete_provider(%Provider{} = provider, %Subject{} = subject) do
|
||||
with :ok <- Authorizer.ensure_has_access_to(provider, subject),
|
||||
:ok <- can_safely_delete?(provider) do
|
||||
Repo.delete(provider)
|
||||
end
|
||||
end
|
||||
|
||||
def soft_delete_provider(%Provider{} = provider, %Subject{} = subject) do
|
||||
provider
|
||||
|> mutate_provider(subject, fn provider ->
|
||||
if other_active_providers_exist?(provider) do
|
||||
:ok = delete_identities_for(provider, subject)
|
||||
{:ok, _groups} = Actors.delete_groups_for(provider, subject)
|
||||
Provider.Changeset.delete_provider(provider)
|
||||
:ok = soft_delete_identities_for(provider, subject)
|
||||
{:ok, _groups} = Actors.soft_delete_groups_for(provider, subject)
|
||||
Provider.Changeset.soft_delete_provider(provider)
|
||||
else
|
||||
:cant_delete_the_last_provider
|
||||
end
|
||||
@@ -326,6 +344,14 @@ defmodule Domain.Auth do
|
||||
end
|
||||
end
|
||||
|
||||
defp can_safely_delete?(%Provider{} = provider) do
|
||||
if other_active_providers_exist?(provider) do
|
||||
:ok
|
||||
else
|
||||
{:error, :cant_delete_the_last_provider}
|
||||
end
|
||||
end
|
||||
|
||||
defp other_active_providers_exist?(%Provider{id: id, account_id: account_id}) do
|
||||
Provider.Query.not_disabled()
|
||||
|> Provider.Query.by_id({:not, id})
|
||||
@@ -425,6 +451,7 @@ defmodule Domain.Auth do
|
||||
end
|
||||
|
||||
# used by IdP adapters
|
||||
# TODO: HARD-DELETE - Remove `unsafe_fragment` after `deleted_at` column is removed from DB
|
||||
def upsert_identity(%Actors.Actor{} = actor, %Provider{} = provider, attrs) do
|
||||
Identity.Changeset.create_identity(actor, provider, attrs)
|
||||
|> Adapters.identity_changeset(provider)
|
||||
@@ -471,6 +498,42 @@ defmodule Domain.Auth do
|
||||
end
|
||||
|
||||
def delete_identity(%Identity{} = identity, %Subject{} = subject) do
|
||||
with :ok <- Authorizer.ensure_has_access_to(identity, subject) do
|
||||
Repo.delete(identity)
|
||||
end
|
||||
end
|
||||
|
||||
def delete_identities_for(%Actors.Actor{} = actor, %Subject{} = subject) do
|
||||
with :ok <- ensure_has_permissions(subject, Authorizer.manage_identities_permission()) do
|
||||
{num_deleted, _} =
|
||||
Identity.Query.all()
|
||||
|> Identity.Query.by_actor_id(actor.id)
|
||||
|> Identity.Query.by_account_id(actor.account_id)
|
||||
|> Authorizer.for_subject(Identity, subject)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE
|
||||
# This function should not be necessary after hard delete because deleting a provider
|
||||
# will delete all of it's identities using a cascading delete in the DB
|
||||
def delete_identities_for(%Provider{} = provider, %Subject{} = subject) do
|
||||
with :ok <- ensure_has_permissions(subject, Authorizer.manage_identities_permission()) do
|
||||
{num_deleted, _} =
|
||||
Identity.Query.all()
|
||||
|> Identity.Query.by_provider_id(provider.id)
|
||||
|> Identity.Query.by_account_id(provider.account_id)
|
||||
|> Authorizer.for_subject(Identity, subject)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB
|
||||
def soft_delete_identity(%Identity{} = identity, %Subject{} = subject) do
|
||||
required_permissions =
|
||||
{:one_of,
|
||||
[
|
||||
@@ -484,30 +547,33 @@ defmodule Domain.Auth do
|
||||
|> Authorizer.for_subject(Identity, subject)
|
||||
|> Repo.fetch_and_update(Identity.Query,
|
||||
with: fn identity ->
|
||||
{:ok, _tokens} = Tokens.delete_tokens_for(identity, subject)
|
||||
{:ok, _tokens} = Tokens.soft_delete_tokens_for(identity, subject)
|
||||
Identity.Changeset.delete_identity(identity)
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def delete_identities_for(%Actors.Actor{} = actor, %Subject{} = subject) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB
|
||||
def soft_delete_identities_for(%Actors.Actor{} = actor, %Subject{} = subject) do
|
||||
Identity.Query.not_deleted()
|
||||
|> Identity.Query.by_actor_id(actor.id)
|
||||
|> Identity.Query.by_account_id(actor.account_id)
|
||||
|> delete_identities(actor, subject)
|
||||
|> soft_delete_identities(actor, subject)
|
||||
end
|
||||
|
||||
def delete_identities_for(%Provider{} = provider, %Subject{} = subject) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB
|
||||
def soft_delete_identities_for(%Provider{} = provider, %Subject{} = subject) do
|
||||
Identity.Query.not_deleted()
|
||||
|> Identity.Query.by_provider_id(provider.id)
|
||||
|> Identity.Query.by_account_id(provider.account_id)
|
||||
|> delete_identities(provider, subject)
|
||||
|> soft_delete_identities(provider, subject)
|
||||
end
|
||||
|
||||
defp delete_identities(queryable, assoc, subject) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB
|
||||
defp soft_delete_identities(queryable, assoc, subject) do
|
||||
with :ok <- ensure_has_permissions(subject, Authorizer.manage_identities_permission()) do
|
||||
{:ok, _tokens} = Tokens.delete_tokens_for(assoc, subject)
|
||||
{:ok, _tokens} = Tokens.soft_delete_tokens_for(assoc, subject)
|
||||
|
||||
{_count, nil} =
|
||||
queryable
|
||||
@@ -518,8 +584,9 @@ defmodule Domain.Auth do
|
||||
end
|
||||
end
|
||||
|
||||
def identity_deleted?(%{deleted_at: nil}), do: false
|
||||
def identity_deleted?(_identity), do: true
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB
|
||||
def identity_soft_deleted?(%{deleted_at: nil}), do: false
|
||||
def identity_soft_deleted?(_identity), do: true
|
||||
|
||||
# Sign Up / In / Off
|
||||
|
||||
@@ -537,6 +604,7 @@ defmodule Domain.Auth do
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB
|
||||
def sign_in(
|
||||
%Provider{deleted_at: deleted_at},
|
||||
_id_or_provider_identifier,
|
||||
@@ -580,6 +648,7 @@ defmodule Domain.Auth do
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed in DB
|
||||
def sign_in(%Provider{deleted_at: deleted_at}, _token_nonce, _payload, %Context{})
|
||||
when not is_nil(deleted_at) do
|
||||
{:error, :unauthorized}
|
||||
@@ -661,7 +730,7 @@ defmodule Domain.Auth do
|
||||
if IdP was used for Sign In, revokes the IdP token too by redirecting user to IdP logout endpoint.
|
||||
"""
|
||||
def sign_out(%Subject{} = subject, redirect_url) do
|
||||
{:ok, _token} = Tokens.delete_token_for(subject)
|
||||
{:ok, _num_deleted} = Tokens.delete_token_for(subject)
|
||||
identity = Repo.preload(subject.identity, :provider)
|
||||
Adapters.sign_out(identity.provider, identity, redirect_url)
|
||||
end
|
||||
|
||||
@@ -109,9 +109,7 @@ defmodule Domain.Auth.Adapters.Email do
|
||||
|> Identity.Query.by_id(identity.id)
|
||||
|> Repo.fetch_and_update(Identity.Query,
|
||||
with: fn identity ->
|
||||
Identity.Changeset.update_identity_provider_state(identity, %{
|
||||
last_used_token_id: token.id
|
||||
})
|
||||
Identity.Changeset.update_identity_provider_state(identity, %{})
|
||||
end
|
||||
)
|
||||
|
||||
|
||||
@@ -67,6 +67,30 @@ defmodule Domain.Auth.Authorizer do
|
||||
[]
|
||||
end
|
||||
|
||||
def ensure_has_access_to(%Auth.Identity{} = identity, %Auth.Subject{} = subject) do
|
||||
cond do
|
||||
# If identity belongs to same actor, check own permission
|
||||
subject.account.id == identity.account_id and owns_identity?(identity, subject) ->
|
||||
Auth.ensure_has_permissions(subject, manage_own_identities_permission())
|
||||
|
||||
# Otherwise, check global manage permission
|
||||
subject.account.id == identity.account_id ->
|
||||
Auth.ensure_has_permissions(subject, manage_identities_permission())
|
||||
|
||||
# Different account
|
||||
true ->
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_has_access_to(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do
|
||||
if subject.account.id == provider.account_id do
|
||||
Auth.ensure_has_permissions(subject, manage_providers_permission())
|
||||
else
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
def for_subject(queryable, Auth.Identity, %Auth.Subject{} = subject) do
|
||||
cond do
|
||||
Auth.has_permission?(subject, manage_identities_permission()) ->
|
||||
@@ -85,4 +109,12 @@ defmodule Domain.Auth.Authorizer do
|
||||
Auth.Provider.Query.by_account_id(queryable, subject.account.id)
|
||||
end
|
||||
end
|
||||
|
||||
defp owns_identity?(%Auth.Identity{} = identity, %Auth.Subject{} = subject) do
|
||||
cond do
|
||||
is_nil(subject.identity) -> false
|
||||
identity.id == subject.identity.id -> true
|
||||
true -> false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -23,10 +23,13 @@ defmodule Domain.Auth.Identity do
|
||||
field :created_by, Ecto.Enum, values: ~w[system provider identity]a
|
||||
field :created_by_subject, :map
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :clients, Domain.Clients.Client, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :tokens, Domain.Tokens.Token, foreign_key: :identity_id, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps(updated_at: false)
|
||||
end
|
||||
|
||||
@@ -82,6 +82,7 @@ defmodule Domain.Auth.Identity.Changeset do
|
||||
|> put_change(:provider_virtual_state, virtual_state)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def delete_identity(%Identity{} = identity) do
|
||||
identity
|
||||
|> change()
|
||||
|
||||
@@ -5,16 +5,19 @@ defmodule Domain.Auth.Identity.Query do
|
||||
from(identities in Domain.Auth.Identity, as: :identities)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def not_deleted do
|
||||
all()
|
||||
|> where([identities: identities], is_nil(identities.deleted_at))
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def deleted do
|
||||
all()
|
||||
|> where([identities: identities], not is_nil(identities.deleted_at))
|
||||
end
|
||||
|
||||
# TODO: Update after `deleted_at` is removed from DB
|
||||
def not_disabled(queryable \\ not_deleted()) do
|
||||
queryable
|
||||
|> with_assoc(:inner, :actor)
|
||||
@@ -144,6 +147,7 @@ defmodule Domain.Auth.Identity.Query do
|
||||
})
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def delete(queryable) do
|
||||
queryable
|
||||
|> Ecto.Query.select([identities: identities], identities)
|
||||
|
||||
@@ -50,6 +50,7 @@ defmodule Domain.Auth.Identity.Sync do
|
||||
{:ok, identities}
|
||||
end
|
||||
|
||||
# TODO: Update after `deleted_at` is removed from DB
|
||||
defp plan_identities_update(identities, provider_identifiers) do
|
||||
{insert, update, delete} =
|
||||
Enum.reduce(
|
||||
@@ -116,22 +117,14 @@ defmodule Domain.Auth.Identity.Sync do
|
||||
end
|
||||
|
||||
defp delete_identities(provider, provider_identifiers_to_delete) do
|
||||
provider_identifiers_to_delete = Enum.uniq(provider_identifiers_to_delete)
|
||||
|
||||
{_count, identities} =
|
||||
Identity.Query.not_deleted()
|
||||
{num_deleted, _} =
|
||||
Identity.Query.all()
|
||||
|> Identity.Query.by_account_id(provider.account_id)
|
||||
|> Identity.Query.by_provider_id(provider.id)
|
||||
|> Identity.Query.by_provider_identifier({:in, provider_identifiers_to_delete})
|
||||
|> Identity.Query.delete()
|
||||
|> Repo.update_all([])
|
||||
|> Repo.delete_all()
|
||||
|
||||
:ok =
|
||||
Enum.each(identities, fn identity ->
|
||||
{:ok, _tokens} = Domain.Tokens.delete_tokens_for(identity)
|
||||
end)
|
||||
|
||||
{:ok, identities}
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
|
||||
defp insert_identities(provider, attrs_by_provider_identifier, provider_identifiers_to_insert) do
|
||||
@@ -153,6 +146,7 @@ defmodule Domain.Auth.Identity.Sync do
|
||||
end)
|
||||
end
|
||||
|
||||
# TODO: Update after `deleted_at` is removed from DB
|
||||
defp update_identities_and_actors(
|
||||
identities,
|
||||
attrs_by_provider_identifier,
|
||||
|
||||
@@ -14,6 +14,7 @@ defmodule Domain.Auth.Provider do
|
||||
|
||||
belongs_to :account, Domain.Accounts.Account
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from DB
|
||||
has_many :actor_groups, Domain.Actors.Group, where: [deleted_at: nil]
|
||||
has_many :identities, Domain.Auth.Identity, where: [deleted_at: nil]
|
||||
|
||||
@@ -27,6 +28,8 @@ defmodule Domain.Auth.Provider do
|
||||
field :sync_error_emailed_at, :utc_datetime_usec
|
||||
|
||||
field :disabled_at, :utc_datetime_usec
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
field :assigned_default_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
|
||||
@@ -4,6 +4,7 @@ defmodule Domain.Auth.Provider.Changeset do
|
||||
alias Domain.Auth.{Subject, Provider, Adapters}
|
||||
|
||||
@create_fields ~w[id name adapter provisioner adapter_config adapter_state disabled_at assigned_default_at]a
|
||||
# TODO: HARD-DELETE - Update after `deleted_at` is removed from DB
|
||||
@update_fields ~w[name adapter_config
|
||||
last_syncs_failed last_sync_error sync_disabled_at sync_error_emailed_at
|
||||
adapter_state provisioner disabled_at deleted_at]a
|
||||
@@ -131,7 +132,8 @@ defmodule Domain.Auth.Provider.Changeset do
|
||||
|> put_change(:disabled_at, nil)
|
||||
end
|
||||
|
||||
def delete_provider(%Provider{} = provider) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def soft_delete_provider(%Provider{} = provider) do
|
||||
provider
|
||||
|> change()
|
||||
|> put_default_value(:deleted_at, DateTime.utc_now())
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Auth.Provider.Query do
|
||||
from(provider in Domain.Auth.Provider, as: :providers)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from the DB
|
||||
def not_deleted do
|
||||
all()
|
||||
|> where([providers: providers], is_nil(providers.deleted_at))
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Auth.Roles do
|
||||
[
|
||||
Domain.Accounts.Authorizer,
|
||||
Domain.Actors.Authorizer,
|
||||
Domain.Actors.Group.Authorizer,
|
||||
Domain.Auth.Authorizer,
|
||||
Domain.Billing.Authorizer,
|
||||
Domain.Clients.Authorizer,
|
||||
|
||||
@@ -186,7 +186,7 @@ defmodule Domain.Clients do
|
||||
end
|
||||
|
||||
def update_client(%Client{} = client, attrs, %Auth.Subject{} = subject) do
|
||||
with :ok <- authorize_actor_client_management(client.actor_id, subject) do
|
||||
with :ok <- Authorizer.ensure_has_access_to(client, subject) do
|
||||
Client.Query.not_deleted()
|
||||
|> Client.Query.by_id(client.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
@@ -198,7 +198,7 @@ defmodule Domain.Clients do
|
||||
end
|
||||
|
||||
def verify_client(%Client{} = client, %Auth.Subject{} = subject) do
|
||||
with :ok <- authorize_actor_client_management(client.actor_id, subject),
|
||||
with :ok <- Authorizer.ensure_has_access_to(client, subject),
|
||||
:ok <- Auth.ensure_has_permissions(subject, Authorizer.verify_clients_permission()) do
|
||||
Client.Query.not_deleted()
|
||||
|> Client.Query.by_id(client.id)
|
||||
@@ -211,7 +211,7 @@ defmodule Domain.Clients do
|
||||
end
|
||||
|
||||
def remove_client_verification(%Client{} = client, %Auth.Subject{} = subject) do
|
||||
with :ok <- authorize_actor_client_management(client.actor_id, subject),
|
||||
with :ok <- Authorizer.ensure_has_access_to(client, subject),
|
||||
:ok <- Auth.ensure_has_permissions(subject, Authorizer.verify_clients_permission()) do
|
||||
Client.Query.not_deleted()
|
||||
|> Client.Query.by_id(client.id)
|
||||
@@ -224,18 +224,8 @@ defmodule Domain.Clients do
|
||||
end
|
||||
|
||||
def delete_client(%Client{} = client, %Auth.Subject{} = subject) do
|
||||
queryable =
|
||||
Client.Query.not_deleted()
|
||||
|> Client.Query.by_id(client.id)
|
||||
|
||||
with :ok <- authorize_actor_client_management(client.actor_id, subject) do
|
||||
case delete_clients(queryable, subject) do
|
||||
{:ok, [client]} ->
|
||||
{:ok, client}
|
||||
|
||||
{:ok, []} ->
|
||||
{:error, :not_found}
|
||||
end
|
||||
with :ok <- Authorizer.ensure_has_access_to(client, subject) do
|
||||
Repo.delete(client)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -245,35 +235,24 @@ defmodule Domain.Clients do
|
||||
|> Client.Query.by_actor_id(actor.id)
|
||||
|> Client.Query.by_account_id(actor.account_id)
|
||||
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_clients_permission()) do
|
||||
{:ok, _clients} = delete_clients(queryable, subject)
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_clients_permission()),
|
||||
:ok <- delete_clients(queryable, subject) do
|
||||
:ok
|
||||
else
|
||||
{:error, reason} -> {:error, reason}
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Hard delete
|
||||
# TODO: HARD-DELETE
|
||||
# We don't necessarily want to delete associated tokens when deleting a client because
|
||||
# that token could be a multi-owner token in the case of a headless client.
|
||||
# Instead we need to introduce the concept of ephemeral clients/gateways and permanent ones.
|
||||
defp delete_clients(queryable, subject) do
|
||||
{_count, clients} =
|
||||
{_count, nil} =
|
||||
queryable
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Client.Query.delete()
|
||||
|> Repo.update_all([])
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, clients}
|
||||
end
|
||||
|
||||
defp authorize_actor_client_management(%Actors.Actor{} = actor, %Auth.Subject{} = subject) do
|
||||
authorize_actor_client_management(actor.id, subject)
|
||||
end
|
||||
|
||||
defp authorize_actor_client_management(id, %Auth.Subject{actor: %{id: id}} = subject) do
|
||||
Auth.ensure_has_permissions(subject, Authorizer.manage_own_clients_permission())
|
||||
end
|
||||
|
||||
defp authorize_actor_client_management(_actor_id, %Auth.Subject{} = subject) do
|
||||
Auth.ensure_has_permissions(subject, Authorizer.manage_clients_permission())
|
||||
:ok
|
||||
end
|
||||
end
|
||||
|
||||
@@ -52,4 +52,21 @@ defmodule Domain.Clients.Authorizer do
|
||||
|> Client.Query.by_actor_id(subject.actor.id)
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_has_access_to(%Client{} = client, %Subject{} = subject) do
|
||||
cond do
|
||||
# If client belongs to same actor, check own permission
|
||||
client.account_id == subject.account.id and
|
||||
client.actor_id == subject.actor.id ->
|
||||
Domain.Auth.ensure_has_permissions(subject, manage_own_clients_permission())
|
||||
|
||||
# Otherwise, check global manage permission
|
||||
client.account_id == subject.account.id ->
|
||||
Domain.Auth.ensure_has_permissions(subject, manage_clients_permission())
|
||||
|
||||
# Different account
|
||||
true ->
|
||||
{:error, {:unauthorized, reason: :incorrect_account}}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -21,7 +21,6 @@ defmodule Domain.Clients.Client do
|
||||
account_id: Ecto.UUID.t(),
|
||||
actor_id: Ecto.UUID.t(),
|
||||
identity_id: Ecto.UUID.t(),
|
||||
last_used_token_id: Ecto.UUID.t(),
|
||||
device_serial: String.t() | nil,
|
||||
device_uuid: String.t() | nil,
|
||||
identifier_for_vendor: String.t() | nil,
|
||||
@@ -59,7 +58,6 @@ defmodule Domain.Clients.Client do
|
||||
belongs_to :account, Domain.Accounts.Account
|
||||
belongs_to :actor, Domain.Actors.Actor
|
||||
belongs_to :identity, Domain.Auth.Identity
|
||||
belongs_to :last_used_token, Domain.Tokens.Token
|
||||
|
||||
# Hardware Identifiers
|
||||
field :device_serial, :string
|
||||
@@ -72,6 +70,7 @@ defmodule Domain.Clients.Client do
|
||||
field :verified_by, Ecto.Enum, values: [:system, :actor, :identity]
|
||||
field :verified_by_subject, :map
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ defmodule Domain.Clients.Client.Changeset do
|
||||
alias Domain.{Version, Auth, Actors}
|
||||
alias Domain.Clients
|
||||
|
||||
@required_fields ~w[external_id last_used_token_id name public_key]a
|
||||
@required_fields ~w[external_id name public_key]a
|
||||
@hardware_identifiers ~w[device_serial device_uuid identifier_for_vendor firebase_installation_id]a
|
||||
@upsert_fields @required_fields ++ @hardware_identifiers
|
||||
@update_fields ~w[name]a
|
||||
@@ -12,6 +12,7 @@ defmodule Domain.Clients.Client.Changeset do
|
||||
# WireGuard base64-encoded string length
|
||||
@key_length 44
|
||||
|
||||
# TODO: Update or remove after `deleted_at` is removed from DB
|
||||
def upsert_conflict_target,
|
||||
do: {:unsafe_fragment, ~s/(account_id, actor_id, external_id) WHERE deleted_at IS NULL/}
|
||||
|
||||
@@ -20,7 +21,6 @@ defmodule Domain.Clients.Client.Changeset do
|
||||
|> update([clients: clients],
|
||||
set: [
|
||||
public_key: fragment("EXCLUDED.public_key"),
|
||||
last_used_token_id: fragment("EXCLUDED.last_used_token_id"),
|
||||
last_seen_user_agent: fragment("EXCLUDED.last_seen_user_agent"),
|
||||
last_seen_remote_ip: fragment("EXCLUDED.last_seen_remote_ip"),
|
||||
last_seen_remote_ip_location_region:
|
||||
@@ -108,7 +108,6 @@ defmodule Domain.Clients.Client.Changeset do
|
||||
|> cast(attrs, @upsert_fields)
|
||||
|> put_default_value(:name, &generate_name/0)
|
||||
|> put_assocs(actor_or_identity)
|
||||
|> put_change(:last_used_token_id, subject.token_id)
|
||||
|> put_change(:last_seen_user_agent, subject.context.user_agent)
|
||||
|> put_change(:last_seen_remote_ip, %Postgrex.INET{address: subject.context.remote_ip})
|
||||
|> put_change(:last_seen_remote_ip_location_region, subject.context.remote_ip_location_region)
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Clients.Client.Query do
|
||||
from(clients in Domain.Clients.Client, as: :clients)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def not_deleted do
|
||||
all()
|
||||
|> where([clients: clients], is_nil(clients.deleted_at))
|
||||
@@ -34,10 +35,6 @@ defmodule Domain.Clients.Client.Query do
|
||||
where(queryable, [clients: clients], clients.account_id == ^account_id)
|
||||
end
|
||||
|
||||
def by_last_used_token_id(queryable, last_used_token_id) do
|
||||
where(queryable, [clients: clients], clients.last_used_token_id == ^last_used_token_id)
|
||||
end
|
||||
|
||||
def by_last_seen_within(queryable, period, unit) do
|
||||
where(queryable, [clients: clients], clients.last_seen_at > ago(^period, ^unit))
|
||||
end
|
||||
@@ -61,7 +58,8 @@ defmodule Domain.Clients.Client.Query do
|
||||
select(queryable, [clients: clients], clients)
|
||||
end
|
||||
|
||||
def delete(queryable) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from the DB
|
||||
def soft_delete(queryable) do
|
||||
queryable
|
||||
|> Ecto.Query.select([clients: clients], clients)
|
||||
|> Ecto.Query.update([clients: clients],
|
||||
|
||||
@@ -6,9 +6,9 @@ defmodule Domain.Clients.Presence do
|
||||
alias Domain.PubSub
|
||||
alias Domain.Clients.Client
|
||||
|
||||
def connect(%Client{} = client) do
|
||||
def connect(%Client{} = client, token_id) do
|
||||
with {:ok, _} <- __MODULE__.Account.track(client.account_id, client.id),
|
||||
{:ok, _} <- __MODULE__.Actor.track(client.actor_id, client.id) do
|
||||
{:ok, _} <- __MODULE__.Actor.track(client.actor_id, client.id, token_id) do
|
||||
:ok
|
||||
end
|
||||
end
|
||||
@@ -47,12 +47,12 @@ defmodule Domain.Clients.Presence do
|
||||
end
|
||||
|
||||
defmodule Actor do
|
||||
def track(actor_id, client_id) do
|
||||
def track(actor_id, client_id, token_id) do
|
||||
Domain.Clients.Presence.track(
|
||||
self(),
|
||||
topic(actor_id),
|
||||
client_id,
|
||||
%{}
|
||||
%{token_id: token_id}
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ defmodule Domain.Gateways do
|
||||
alias Domain.{Repo, Auth, Geo}
|
||||
alias Domain.{Accounts, Cache, Clients, Resources, Tokens, Billing}
|
||||
alias Domain.Gateways.{Authorizer, Gateway, Group, Presence}
|
||||
require Logger
|
||||
|
||||
require Logger
|
||||
|
||||
@@ -137,24 +138,8 @@ defmodule Domain.Gateways do
|
||||
end
|
||||
|
||||
def delete_group(%Group{managed_by: :account} = group, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_gateways_permission()) do
|
||||
Group.Query.not_deleted()
|
||||
|> Group.Query.by_id(group.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.fetch_and_update(Group.Query,
|
||||
with: fn group ->
|
||||
# Token deletion will disconnect gateways
|
||||
{:ok, _tokens} = Tokens.delete_tokens_for(group, subject)
|
||||
{:ok, _count} = Resources.delete_connections_for(group, subject)
|
||||
|
||||
{_count, _} =
|
||||
Gateway.Query.not_deleted()
|
||||
|> Gateway.Query.by_group_id(group.id)
|
||||
|> Repo.update_all(set: [deleted_at: DateTime.utc_now()])
|
||||
|
||||
Group.Changeset.delete(group)
|
||||
end
|
||||
)
|
||||
with :ok <- Authorizer.ensure_has_access_to(group, subject) do
|
||||
Repo.delete(group)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -294,8 +279,8 @@ defmodule Domain.Gateways do
|
||||
Gateway.Changeset.update(gateway, attrs)
|
||||
end
|
||||
|
||||
def upsert_gateway(%Group{} = group, %Tokens.Token{} = token, attrs, %Auth.Context{} = context) do
|
||||
changeset = Gateway.Changeset.upsert(group, token, attrs, context)
|
||||
def upsert_gateway(%Group{} = group, attrs, %Auth.Context{} = context) do
|
||||
changeset = Gateway.Changeset.upsert(group, attrs, context)
|
||||
|
||||
Ecto.Multi.new()
|
||||
|> Ecto.Multi.insert(:gateway, changeset,
|
||||
@@ -338,18 +323,25 @@ defmodule Domain.Gateways do
|
||||
end
|
||||
end
|
||||
|
||||
def delete_gateway(%Gateway{} = gateway, %Auth.Subject{} = subject) do
|
||||
# TODO: HARD-DELETE - Remove this once deleted_at field is gone
|
||||
def soft_delete_gateway(%Gateway{} = gateway, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_gateways_permission()) do
|
||||
Gateway.Query.not_deleted()
|
||||
|> Gateway.Query.by_id(gateway.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.fetch_and_update(Gateway.Query,
|
||||
with: &Gateway.Changeset.delete/1,
|
||||
with: &Gateway.Changeset.soft_delete/1,
|
||||
preload: [:online?]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def delete_gateway(%Gateway{} = gateway, %Auth.Subject{} = subject) do
|
||||
with :ok <- Authorizer.ensure_has_access_to(gateway, subject) do
|
||||
Repo.delete(gateway)
|
||||
end
|
||||
end
|
||||
|
||||
def load_balance_gateways({_lat, _lon}, []) do
|
||||
nil
|
||||
end
|
||||
|
||||
@@ -27,6 +27,22 @@ defmodule Domain.Gateways.Authorizer do
|
||||
]
|
||||
end
|
||||
|
||||
def ensure_has_access_to(%Group{} = group, %Subject{} = subject) do
|
||||
if group.account_id == subject.account.id do
|
||||
Domain.Auth.ensure_has_permissions(subject, manage_gateways_permission())
|
||||
else
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_has_access_to(%Gateway{} = gateway, %Subject{} = subject) do
|
||||
if gateway.account_id == subject.account.id do
|
||||
Domain.Auth.ensure_has_permissions(subject, manage_gateways_permission())
|
||||
else
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@impl Domain.Auth.Authorizer
|
||||
def for_subject(queryable, %Subject{} = subject) do
|
||||
cond do
|
||||
|
||||
@@ -45,13 +45,12 @@ defmodule Domain.Gateways.Gateway do
|
||||
field :last_seen_version, :string
|
||||
field :last_seen_at, :utc_datetime_usec
|
||||
|
||||
belongs_to :last_used_token, Domain.Tokens.Token
|
||||
|
||||
field :online?, :boolean, virtual: true
|
||||
|
||||
belongs_to :account, Domain.Accounts.Account
|
||||
belongs_to :group, Domain.Gateways.Group
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
defmodule Domain.Gateways.Gateway.Changeset do
|
||||
use Domain, :changeset
|
||||
alias Domain.{Version, Auth, Tokens}
|
||||
alias Domain.{Version, Auth}
|
||||
alias Domain.Gateways
|
||||
|
||||
@upsert_fields ~w[external_id name public_key
|
||||
@@ -20,7 +20,6 @@ defmodule Domain.Gateways.Gateway.Changeset do
|
||||
last_seen_remote_ip_location_lon
|
||||
last_seen_version
|
||||
last_seen_at
|
||||
last_used_token_id
|
||||
updated_at]a
|
||||
@update_fields ~w[name]a
|
||||
@required_fields ~w[external_id name public_key]a
|
||||
@@ -28,12 +27,13 @@ defmodule Domain.Gateways.Gateway.Changeset do
|
||||
# WireGuard base64-encoded string length
|
||||
@key_length 44
|
||||
|
||||
# TODO: Update or remove after `deleted_at` is removed from DB
|
||||
def upsert_conflict_target,
|
||||
do: {:unsafe_fragment, ~s/(account_id, group_id, external_id) WHERE deleted_at IS NULL/}
|
||||
|
||||
def upsert_on_conflict, do: {:replace, @conflict_replace_fields}
|
||||
|
||||
def upsert(%Gateways.Group{} = group, %Tokens.Token{} = token, attrs, %Auth.Context{} = context) do
|
||||
def upsert(%Gateways.Group{} = group, attrs, %Auth.Context{} = context) do
|
||||
%Gateways.Gateway{}
|
||||
|> cast(attrs, @upsert_fields)
|
||||
|> put_default_value(:name, fn ->
|
||||
@@ -56,7 +56,6 @@ defmodule Domain.Gateways.Gateway.Changeset do
|
||||
|> put_gateway_version()
|
||||
|> put_change(:account_id, group.account_id)
|
||||
|> put_change(:group_id, group.id)
|
||||
|> put_change(:last_used_token_id, token.id)
|
||||
end
|
||||
|
||||
def finalize_upsert(%Gateways.Gateway{} = gateway, ipv4, ipv6) do
|
||||
@@ -73,7 +72,8 @@ defmodule Domain.Gateways.Gateway.Changeset do
|
||||
|> validate_required(@required_fields)
|
||||
end
|
||||
|
||||
def delete(%Gateways.Gateway{} = gateway) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def soft_delete(%Gateways.Gateway{} = gateway) do
|
||||
gateway
|
||||
|> change()
|
||||
|> put_default_value(:deleted_at, DateTime.utc_now())
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Gateways.Gateway.Query do
|
||||
from(gateways in Domain.Gateways.Gateway, as: :gateways)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def not_deleted do
|
||||
all()
|
||||
|> where([gateways: gateways], is_nil(gateways.deleted_at))
|
||||
@@ -107,6 +108,7 @@ defmodule Domain.Gateways.Gateway.Query do
|
||||
{queryable, dynamic([gateways: gateways], gateways.id in ^ids)}
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def filter_deleted(queryable) do
|
||||
{queryable, dynamic([gateways: gateways], not is_nil(gateways.deleted_at))}
|
||||
end
|
||||
|
||||
@@ -19,8 +19,10 @@ defmodule Domain.Gateways.Group do
|
||||
field :managed_by, Ecto.Enum, values: ~w[account system]a
|
||||
|
||||
belongs_to :account, Domain.Accounts.Account
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` column is remove
|
||||
has_many :gateways, Domain.Gateways.Gateway, foreign_key: :group_id, where: [deleted_at: nil]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` column is remove
|
||||
has_many :tokens, Domain.Tokens.Token,
|
||||
foreign_key: :gateway_group_id,
|
||||
where: [deleted_at: nil]
|
||||
@@ -30,6 +32,7 @@ defmodule Domain.Gateways.Group do
|
||||
field :created_by, Ecto.Enum, values: ~w[actor identity system]a
|
||||
field :created_by_subject, :map
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@@ -40,6 +40,7 @@ defmodule Domain.Gateways.Group.Changeset do
|
||||
|> unique_constraint(:name, name: :gateway_groups_account_id_name_managed_by_index)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from the DB
|
||||
def delete(%Gateways.Group{} = group) do
|
||||
group
|
||||
|> change()
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Gateways.Group.Query do
|
||||
from(groups in Domain.Gateways.Group, as: :groups)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def not_deleted do
|
||||
all()
|
||||
|> where([groups: groups], is_nil(groups.deleted_at))
|
||||
@@ -56,6 +57,7 @@ defmodule Domain.Gateways.Group.Query do
|
||||
}
|
||||
]
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def filter_deleted(queryable) do
|
||||
{queryable, dynamic([groups: groups], not is_nil(groups.deleted_at))}
|
||||
end
|
||||
|
||||
@@ -6,8 +6,8 @@ defmodule Domain.Gateways.Presence do
|
||||
alias Domain.Gateways.Gateway
|
||||
alias Domain.PubSub
|
||||
|
||||
def connect(%Gateway{} = gateway) do
|
||||
with {:ok, _} <- __MODULE__.Group.track(gateway.group_id, gateway.id),
|
||||
def connect(%Gateway{} = gateway, token_id) do
|
||||
with {:ok, _} <- __MODULE__.Group.track(gateway.group_id, gateway.id, token_id),
|
||||
{:ok, _} <- __MODULE__.Account.track(gateway.account_id, gateway.id) do
|
||||
:ok
|
||||
end
|
||||
@@ -47,12 +47,12 @@ defmodule Domain.Gateways.Presence do
|
||||
end
|
||||
|
||||
defmodule Group do
|
||||
def track(gateway_group_id, gateway_id) do
|
||||
def track(gateway_group_id, gateway_id, token_id) do
|
||||
Domain.Gateways.Presence.track(
|
||||
self(),
|
||||
topic(gateway_group_id),
|
||||
gateway_id,
|
||||
%{}
|
||||
%{token_id: token_id}
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ defmodule Domain.Policies do
|
||||
alias Domain.Repo
|
||||
alias Domain.{Auth, Actors, Cache.Cacheable, Clients, Resources}
|
||||
alias Domain.Policies.{Authorizer, Policy, Condition}
|
||||
require Logger
|
||||
|
||||
def fetch_policy_by_id(id, %Auth.Subject{} = subject, opts \\ []) do
|
||||
required_permissions =
|
||||
@@ -138,10 +139,11 @@ defmodule Domain.Policies do
|
||||
end
|
||||
end
|
||||
|
||||
def delete_policy(%Policy{} = policy, %Auth.Subject{} = subject) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def soft_delete_policy(%Policy{} = policy, %Auth.Subject{} = subject) do
|
||||
Policy.Query.not_deleted()
|
||||
|> Policy.Query.by_id(policy.id)
|
||||
|> delete_policies(subject)
|
||||
|> soft_delete_policies(subject)
|
||||
|> case do
|
||||
{:ok, [policy]} -> {:ok, policy}
|
||||
{:ok, []} -> {:error, :not_found}
|
||||
@@ -149,39 +151,100 @@ defmodule Domain.Policies do
|
||||
end
|
||||
end
|
||||
|
||||
def delete_policies_for(%Resources.Resource{} = resource, %Auth.Subject{} = subject) do
|
||||
Policy.Query.not_deleted()
|
||||
|> Policy.Query.by_resource_id(resource.id)
|
||||
|> delete_policies(subject)
|
||||
end
|
||||
|
||||
def delete_policies_for(%Actors.Group{} = actor_group, %Auth.Subject{} = subject) do
|
||||
Policy.Query.not_deleted()
|
||||
|> Policy.Query.by_actor_group_id(actor_group.id)
|
||||
|> delete_policies(subject)
|
||||
end
|
||||
|
||||
def delete_policies_for(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do
|
||||
Policy.Query.not_deleted()
|
||||
|> Policy.Query.by_actor_group_provider_id(provider.id)
|
||||
|> delete_policies(subject)
|
||||
end
|
||||
|
||||
def delete_policies_for(%Actors.Group{} = actor_group) do
|
||||
Policy.Query.not_deleted()
|
||||
|> Policy.Query.by_actor_group_id(actor_group.id)
|
||||
|> delete_policies()
|
||||
end
|
||||
|
||||
defp delete_policies(queryable, subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do
|
||||
queryable
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> delete_policies()
|
||||
def delete_policy(%Policy{} = policy, %Auth.Subject{} = subject) do
|
||||
with :ok <- Authorizer.ensure_has_access_to(policy, subject) do
|
||||
Repo.delete(policy)
|
||||
end
|
||||
end
|
||||
|
||||
defp delete_policies(queryable) do
|
||||
# TODO: HARD-DELETE - Should not be needed after hard delete is implemented
|
||||
def delete_policies_for(%Resources.Resource{} = resource, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do
|
||||
{count, nil} =
|
||||
Policy.Query.all()
|
||||
|> Policy.Query.by_resource_id(resource.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, count}
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Should not be needed after hard delete is implemented
|
||||
def delete_policies_for(%Actors.Group{} = actor_group, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do
|
||||
{count, nil} =
|
||||
Policy.Query.all()
|
||||
|> Policy.Query.by_actor_group_id(actor_group.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, count}
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Should not be needed after hard delete is implemented
|
||||
def delete_policies_for(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do
|
||||
{count, nil} =
|
||||
Policy.Query.all()
|
||||
|> Policy.Query.by_actor_group_provider_id(provider.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, count}
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Should not be needed after hard delete is implemented
|
||||
def delete_policies_for(%Actors.Group{} = actor_group) do
|
||||
{count, nil} =
|
||||
Policy.Query.all()
|
||||
|> Policy.Query.by_actor_group_id(actor_group.id)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, count}
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def soft_delete_policies_for(%Resources.Resource{} = resource, %Auth.Subject{} = subject) do
|
||||
Policy.Query.not_deleted()
|
||||
|> Policy.Query.by_resource_id(resource.id)
|
||||
|> soft_delete_policies(subject)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def soft_delete_policies_for(%Actors.Group{} = actor_group, %Auth.Subject{} = subject) do
|
||||
Policy.Query.not_deleted()
|
||||
|> Policy.Query.by_actor_group_id(actor_group.id)
|
||||
|> soft_delete_policies(subject)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def soft_delete_policies_for(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do
|
||||
Policy.Query.not_deleted()
|
||||
|> Policy.Query.by_actor_group_provider_id(provider.id)
|
||||
|> soft_delete_policies(subject)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def soft_delete_policies_for(%Actors.Group{} = actor_group) do
|
||||
Policy.Query.not_deleted()
|
||||
|> Policy.Query.by_actor_group_id(actor_group.id)
|
||||
|> soft_delete_policies()
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
defp soft_delete_policies(queryable, subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_policies_permission()) do
|
||||
queryable
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> soft_delete_policies()
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
defp soft_delete_policies(queryable) do
|
||||
{_count, policies} =
|
||||
queryable
|
||||
|> Policy.Query.delete()
|
||||
|
||||
@@ -37,6 +37,14 @@ defmodule Domain.Policies.Authorizer do
|
||||
[]
|
||||
end
|
||||
|
||||
def ensure_has_access_to(%Policy{} = policy, %Subject{} = subject) do
|
||||
if policy.account_id == subject.account.id do
|
||||
Domain.Auth.ensure_has_permissions(subject, manage_policies_permission())
|
||||
else
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@impl Domain.Auth.Authorizer
|
||||
def for_subject(queryable, %Subject{} = subject) do
|
||||
cond do
|
||||
|
||||
@@ -36,6 +36,8 @@ defmodule Domain.Policies.Policy do
|
||||
has_one :replaces_policy, Domain.Policies.Policy, foreign_key: :replaced_by_policy_id
|
||||
|
||||
field :disabled_at, :utc_datetime_usec
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Policies.Policy.Query do
|
||||
from(policies in Domain.Policies.Policy, as: :policies)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def not_deleted do
|
||||
all()
|
||||
|> where([policies: policies], is_nil(policies.deleted_at))
|
||||
@@ -84,6 +85,7 @@ defmodule Domain.Policies.Policy.Query do
|
||||
})
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def delete(queryable) do
|
||||
queryable
|
||||
|> Ecto.Query.select([policies: policies], policies)
|
||||
@@ -251,6 +253,7 @@ defmodule Domain.Policies.Policy.Query do
|
||||
{queryable, dynamic([policies: policies], not is_nil(policies.disabled_at))}
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def filter_deleted(queryable) do
|
||||
{queryable, dynamic([policies: policies], not is_nil(policies.deleted_at))}
|
||||
end
|
||||
|
||||
@@ -88,6 +88,13 @@ defmodule Domain.Relays do
|
||||
end
|
||||
|
||||
def delete_group(%Group{} = group, %Auth.Subject{} = subject) do
|
||||
with :ok <- Authorizer.ensure_has_access_to(group, subject) do
|
||||
Repo.delete(group)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def soft_delete_group(%Group{} = group, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_relays_permission()) do
|
||||
Group.Query.not_deleted()
|
||||
|> Group.Query.by_id(group.id)
|
||||
@@ -95,7 +102,7 @@ defmodule Domain.Relays do
|
||||
|> Group.Query.by_account_id(subject.account.id)
|
||||
|> Repo.fetch_and_update(Group.Query,
|
||||
with: fn group ->
|
||||
{:ok, _tokens} = Tokens.delete_tokens_for(group, subject)
|
||||
{:ok, _tokens} = Tokens.soft_delete_tokens_for(group, subject)
|
||||
|
||||
{_count, _} =
|
||||
Relay.Query.not_deleted()
|
||||
@@ -286,8 +293,8 @@ defmodule Domain.Relays do
|
||||
|> Base.encode64(padding: false)
|
||||
end
|
||||
|
||||
def upsert_relay(%Group{} = group, %Tokens.Token{} = token, attrs, %Auth.Context{} = context) do
|
||||
changeset = Relay.Changeset.upsert(group, token, attrs, context)
|
||||
def upsert_relay(%Group{} = group, attrs, %Auth.Context{} = context) do
|
||||
changeset = Relay.Changeset.upsert(group, attrs, context)
|
||||
|
||||
Ecto.Multi.new()
|
||||
|> Ecto.Multi.insert(:relay, changeset,
|
||||
@@ -303,6 +310,13 @@ defmodule Domain.Relays do
|
||||
end
|
||||
|
||||
def delete_relay(%Relay{} = relay, %Auth.Subject{} = subject) do
|
||||
with :ok <- Authorizer.ensure_has_access_to(relay, subject) do
|
||||
Repo.delete(relay)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def soft_delete_relay(%Relay{} = relay, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_relays_permission()) do
|
||||
Relay.Query.not_deleted()
|
||||
|> Relay.Query.by_id(relay.id)
|
||||
@@ -344,10 +358,13 @@ defmodule Domain.Relays do
|
||||
|> Enum.map(&Enum.random(elem(&1, 1)))
|
||||
end
|
||||
|
||||
# TODO: Refactor to use new conventions
|
||||
def connect_relay(%Relay{} = relay, secret) do
|
||||
# TODO: WAL
|
||||
# Refactor to use new conventions
|
||||
def connect_relay(%Relay{} = relay, secret, token_id) do
|
||||
with {:ok, _} <-
|
||||
Presence.track(self(), group_presence_topic(relay.group_id), relay.id, %{}),
|
||||
Presence.track(self(), group_presence_topic(relay.group_id), relay.id, %{
|
||||
token_id: token_id
|
||||
}),
|
||||
{:ok, _} <-
|
||||
Presence.track(self(), account_or_global_presence_topic(relay), relay.id, %{
|
||||
online_at: System.system_time(:second),
|
||||
|
||||
@@ -16,6 +16,24 @@ defmodule Domain.Relays.Authorizer do
|
||||
[]
|
||||
end
|
||||
|
||||
def ensure_has_access_to(%Group{} = group, %Subject{} = subject) do
|
||||
# Allow access to global relay groups or account-specific groups
|
||||
if group.account_id == subject.account.id or is_nil(group.account_id) do
|
||||
Domain.Auth.ensure_has_permissions(subject, manage_relays_permission())
|
||||
else
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_has_access_to(%Relay{} = relay, %Subject{} = subject) do
|
||||
# Allow access to global relays or account-specific relays
|
||||
if relay.account_id == subject.account.id or is_nil(relay.account_id) do
|
||||
Domain.Auth.ensure_has_permissions(subject, manage_relays_permission())
|
||||
else
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@impl Domain.Auth.Authorizer
|
||||
def for_subject(queryable, %Subject{} = subject) do
|
||||
cond do
|
||||
|
||||
@@ -5,12 +5,14 @@ defmodule Domain.Relays.Group do
|
||||
field :name, :string
|
||||
|
||||
belongs_to :account, Domain.Accounts.Account
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :relays, Domain.Relays.Relay, foreign_key: :group_id, where: [deleted_at: nil]
|
||||
has_many :tokens, Domain.Tokens.Token, foreign_key: :relay_group_id, where: [deleted_at: nil]
|
||||
|
||||
field :created_by, Ecto.Enum, values: ~w[system identity]a
|
||||
field :created_by_subject, :map
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@@ -37,6 +37,7 @@ defmodule Domain.Relays.Group.Changeset do
|
||||
|> unique_constraint(:name, name: :relay_groups_account_id_name_index)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from the DB
|
||||
def delete(%Relays.Group{} = group) do
|
||||
group
|
||||
|> change()
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Relays.Group.Query do
|
||||
from(groups in Domain.Relays.Group, as: :groups)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from the DB
|
||||
def not_deleted do
|
||||
all()
|
||||
|> where([groups: groups], is_nil(groups.deleted_at))
|
||||
@@ -55,6 +56,7 @@ defmodule Domain.Relays.Group.Query do
|
||||
}
|
||||
]
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from the DB
|
||||
def filter_deleted(queryable) do
|
||||
{queryable, dynamic([groups: groups], not is_nil(groups.deleted_at))}
|
||||
end
|
||||
|
||||
@@ -18,8 +18,6 @@ defmodule Domain.Relays.Relay do
|
||||
field :last_seen_version, :string
|
||||
field :last_seen_at, :utc_datetime_usec
|
||||
|
||||
belongs_to :last_used_token, Domain.Tokens.Token
|
||||
|
||||
field :stamp_secret, :string, virtual: true
|
||||
|
||||
field :online?, :boolean, virtual: true
|
||||
@@ -27,6 +25,7 @@ defmodule Domain.Relays.Relay do
|
||||
belongs_to :account, Domain.Accounts.Account
|
||||
belongs_to :group, Domain.Relays.Group
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
defmodule Domain.Relays.Relay.Changeset do
|
||||
use Domain, :changeset
|
||||
alias Domain.{Version, Auth, Tokens}
|
||||
alias Domain.{Version, Auth}
|
||||
alias Domain.Relays
|
||||
|
||||
@upsert_fields ~w[ipv4 ipv6 port name
|
||||
@@ -19,14 +19,15 @@ defmodule Domain.Relays.Relay.Changeset do
|
||||
last_seen_remote_ip_location_lon
|
||||
last_seen_version
|
||||
last_seen_at
|
||||
last_used_token_id
|
||||
updated_at]a
|
||||
|
||||
# TODO: HARD-DELETE - Update or remove after `deleted_at` is removed from DB
|
||||
def upsert_conflict_target(%{account_id: nil}) do
|
||||
{:unsafe_fragment,
|
||||
~s/(COALESCE(ipv4, ipv6), port) WHERE deleted_at IS NULL AND account_id IS NULL/}
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Update or remove after `deleted_at` is removed from DB
|
||||
def upsert_conflict_target(%{account_id: _account_id}) do
|
||||
{:unsafe_fragment,
|
||||
~s/(account_id, COALESCE(ipv4, ipv6), port) WHERE deleted_at IS NULL AND account_id IS NOT NULL/}
|
||||
@@ -34,7 +35,7 @@ defmodule Domain.Relays.Relay.Changeset do
|
||||
|
||||
def upsert_on_conflict, do: {:replace, @conflict_replace_fields}
|
||||
|
||||
def upsert(%Relays.Group{} = group, %Tokens.Token{} = token, attrs, %Auth.Context{} = context) do
|
||||
def upsert(%Relays.Group{} = group, attrs, %Auth.Context{} = context) do
|
||||
%Relays.Relay{}
|
||||
|> cast(attrs, @upsert_fields)
|
||||
|> validate_required_one_of(~w[ipv4 ipv6]a)
|
||||
@@ -56,9 +57,9 @@ defmodule Domain.Relays.Relay.Changeset do
|
||||
|> put_relay_version()
|
||||
|> put_change(:account_id, group.account_id)
|
||||
|> put_change(:group_id, group.id)
|
||||
|> put_change(:last_used_token_id, token.id)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def delete(%Relays.Relay{} = relay) do
|
||||
relay
|
||||
|> change()
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Relays.Relay.Query do
|
||||
from(relays in Domain.Relays.Relay, as: :relays)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def not_deleted do
|
||||
all()
|
||||
|> where([relays: relays], is_nil(relays.deleted_at))
|
||||
@@ -54,6 +55,7 @@ defmodule Domain.Relays.Relay.Query do
|
||||
order_by(queryable, [relays: relays], asc_nulls_first: relays.account_id)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove or possibly rename after `deleted_at` is removed from DB
|
||||
def returning_not_deleted(queryable) do
|
||||
select(queryable, [relays: relays], relays)
|
||||
end
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
defmodule Domain.Resources do
|
||||
alias Domain.{Repo, Auth}
|
||||
alias Domain.{Accounts, Gateways, Policies}
|
||||
alias Domain.{Accounts, Gateways}
|
||||
alias Domain.Resources.{Authorizer, Resource, Connection}
|
||||
require Logger
|
||||
|
||||
def fetch_resource_by_id(id, %Auth.Subject{} = subject, opts \\ []) do
|
||||
required_permissions =
|
||||
@@ -262,44 +263,28 @@ defmodule Domain.Resources do
|
||||
end
|
||||
|
||||
def delete_resource(%Resource{type: :internet}, %Auth.Subject{}) do
|
||||
{:error, :cannot_delete_internet_resource}
|
||||
{:error, :cant_delete_internet_resource}
|
||||
end
|
||||
|
||||
def delete_resource(%Resource{} = resource, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_resources_permission()) do
|
||||
Resource.Query.not_deleted()
|
||||
|> Resource.Query.by_id(resource.id)
|
||||
|> Authorizer.for_subject(Resource, subject)
|
||||
|> Repo.fetch_and_update(Resource.Query,
|
||||
with: fn resource ->
|
||||
{_count, nil} =
|
||||
Connection.Query.by_resource_id(resource.id)
|
||||
|> Repo.delete_all()
|
||||
|
||||
Resource.Changeset.delete(resource)
|
||||
end
|
||||
)
|
||||
|> case do
|
||||
{:ok, resource} ->
|
||||
{:ok, _policies} = Policies.delete_policies_for(resource, subject)
|
||||
{:ok, resource}
|
||||
|
||||
{:error, reason} ->
|
||||
{:error, reason}
|
||||
end
|
||||
with :ok <- Authorizer.ensure_has_access_to(resource, subject) do
|
||||
Repo.delete(resource)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE (shouldn't be needed)
|
||||
def delete_connections_for(%Gateways.Group{} = gateway_group, %Auth.Subject{} = subject) do
|
||||
Connection.Query.by_gateway_group_id(gateway_group.id)
|
||||
|> delete_connections(subject)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE (shouldn't be needed)
|
||||
def delete_connections_for(%Resource{} = resource, %Auth.Subject{} = subject) do
|
||||
Connection.Query.by_resource_id(resource.id)
|
||||
|> delete_connections(subject)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE (shouldn't be needed)
|
||||
defp delete_connections(queryable, subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_resources_permission()) do
|
||||
{count, nil} =
|
||||
|
||||
@@ -36,6 +36,14 @@ defmodule Domain.Resources.Authorizer do
|
||||
[]
|
||||
end
|
||||
|
||||
def ensure_has_access_to(%Resource{} = resource, %Subject{} = subject) do
|
||||
if resource.account_id == subject.account.id do
|
||||
Domain.Auth.ensure_has_permissions(subject, manage_resources_permission())
|
||||
else
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
def for_subject(queryable, Connection, %Subject{} = subject) do
|
||||
cond do
|
||||
has_permission?(subject, manage_resources_permission()) ->
|
||||
|
||||
@@ -45,6 +45,7 @@ defmodule Domain.Resources.Resource do
|
||||
# ref https://github.com/firezone/firezone/issues/2162
|
||||
has_many :gateway_groups, through: [:connections, :gateway_group]
|
||||
|
||||
# TODO: HARD-DELETE - Remove `where` after `deleted_at` is removed from the DB
|
||||
has_many :policies, Domain.Policies.Policy, where: [deleted_at: nil]
|
||||
has_many :actor_groups, through: [:policies, :actor_group]
|
||||
|
||||
@@ -58,6 +59,7 @@ defmodule Domain.Resources.Resource do
|
||||
belongs_to :replaced_by_resource, Domain.Resources.Resource
|
||||
has_one :replaces_resource, Domain.Resources.Resource, foreign_key: :replaced_by_resource_id
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@@ -67,6 +67,7 @@ defmodule Domain.Resources.Resource.Changeset do
|
||||
)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def delete(%Resource{} = resource) do
|
||||
resource
|
||||
|> change()
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Resources.Resource.Query do
|
||||
from(resources in Domain.Resources.Resource, as: :resources)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def not_deleted do
|
||||
all()
|
||||
|> where([resources: resources], is_nil(resources.deleted_at))
|
||||
@@ -192,6 +193,7 @@ defmodule Domain.Resources.Resource.Query do
|
||||
dynamic([connections: connections], connections.gateway_group_id == ^gateway_group_id)}
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def filter_deleted(queryable) do
|
||||
{queryable, dynamic([resources: resources], not is_nil(resources.deleted_at))}
|
||||
end
|
||||
|
||||
@@ -4,6 +4,7 @@ defmodule Domain.Tokens do
|
||||
alias Domain.{Auth, Actors, Relays, Gateways}
|
||||
alias Domain.Tokens.{Token, Authorizer, Jobs}
|
||||
require Ecto.Query
|
||||
require Logger
|
||||
|
||||
def start_link(_init_arg) do
|
||||
Supervisor.start_link(__MODULE__, nil, name: __MODULE__)
|
||||
@@ -182,6 +183,113 @@ defmodule Domain.Tokens do
|
||||
end
|
||||
|
||||
def delete_token(%Token{} = token, %Auth.Subject{} = subject) do
|
||||
with :ok <- Authorizer.ensure_has_access_to(token, subject) do
|
||||
Repo.delete(token)
|
||||
end
|
||||
end
|
||||
|
||||
def delete_token_for(%Auth.Subject{} = subject) do
|
||||
{num_deleted, _} =
|
||||
Token.Query.all()
|
||||
|> Token.Query.by_id(subject.token_id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
|
||||
def delete_tokens_for(%Actors.Actor{} = actor, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do
|
||||
{num_deleted, _} =
|
||||
Token.Query.all()
|
||||
|> Token.Query.by_actor_id(actor.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
end
|
||||
|
||||
def delete_tokens_for(%Auth.Identity{} = identity, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.Authorizer.ensure_has_access_to(identity, subject),
|
||||
:ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do
|
||||
{num_deleted, _} =
|
||||
Token.Query.all()
|
||||
|> Token.Query.by_identity_id(identity.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
end
|
||||
|
||||
def delete_tokens_for(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do
|
||||
{num_deleted, _} =
|
||||
Token.Query.all()
|
||||
|> Token.Query.by_provider_id(provider.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
end
|
||||
|
||||
def delete_tokens_for(%Relays.Group{} = group, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do
|
||||
{num_deleted, _} =
|
||||
Token.Query.all()
|
||||
|> Token.Query.by_relay_group_id(group.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
end
|
||||
|
||||
def delete_tokens_for(%Gateways.Group{} = group, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do
|
||||
{num_deleted, _} =
|
||||
Token.Query.all()
|
||||
|> Token.Query.by_gateway_group_id(group.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
end
|
||||
|
||||
def delete_tokens_for(%Auth.Identity{} = identity) do
|
||||
{num_deleted, _} =
|
||||
Token.Query.all()
|
||||
|> Token.Query.by_identity_id(identity.id)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
|
||||
def delete_all_tokens_by_type_and_assoc(:email, %Auth.Identity{} = identity) do
|
||||
{num_deleted, _} =
|
||||
Token.Query.not_deleted()
|
||||
|> Token.Query.by_type(:email)
|
||||
|> Token.Query.by_account_id(identity.account_id)
|
||||
|> Token.Query.by_identity_id(identity.id)
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
|
||||
def delete_expired_tokens do
|
||||
{num_deleted, _} =
|
||||
Token.Query.all()
|
||||
|> Token.Query.expired()
|
||||
|> Repo.delete_all()
|
||||
|
||||
{:ok, num_deleted}
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB
|
||||
def soft_delete_token(%Token{} = token, %Auth.Subject{} = subject) do
|
||||
required_permissions =
|
||||
{:one_of,
|
||||
[
|
||||
@@ -193,7 +301,7 @@ defmodule Domain.Tokens do
|
||||
Token.Query.not_deleted()
|
||||
|> Token.Query.by_id(token.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> delete_tokens()
|
||||
|> soft_delete_tokens()
|
||||
|> case do
|
||||
{:ok, [token]} -> {:ok, token}
|
||||
{:ok, []} -> {:error, :not_found}
|
||||
@@ -201,79 +309,89 @@ defmodule Domain.Tokens do
|
||||
end
|
||||
end
|
||||
|
||||
def delete_token_for(%Auth.Subject{} = subject) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB
|
||||
def soft_delete_token_for(%Auth.Subject{} = subject) do
|
||||
Token.Query.not_deleted()
|
||||
|> Token.Query.by_id(subject.token_id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> delete_tokens()
|
||||
|> soft_delete_tokens()
|
||||
end
|
||||
|
||||
def delete_tokens_for(%Auth.Identity{} = identity) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB
|
||||
def soft_delete_tokens_for(%Auth.Identity{} = identity) do
|
||||
Token.Query.not_deleted()
|
||||
|> Token.Query.by_identity_id(identity.id)
|
||||
|> delete_tokens()
|
||||
|> soft_delete_tokens()
|
||||
end
|
||||
|
||||
def delete_tokens_for(%Actors.Actor{} = actor, %Auth.Subject{} = subject) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB
|
||||
def soft_delete_tokens_for(%Actors.Actor{} = actor, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do
|
||||
Token.Query.not_deleted()
|
||||
|> Token.Query.by_actor_id(actor.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> delete_tokens()
|
||||
|> soft_delete_tokens()
|
||||
end
|
||||
end
|
||||
|
||||
def delete_tokens_for(%Auth.Identity{} = identity, %Auth.Subject{} = subject) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB
|
||||
def soft_delete_tokens_for(%Auth.Identity{} = identity, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do
|
||||
Token.Query.not_deleted()
|
||||
|> Token.Query.by_identity_id(identity.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> delete_tokens()
|
||||
|> soft_delete_tokens()
|
||||
end
|
||||
end
|
||||
|
||||
def delete_tokens_for(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB
|
||||
def soft_delete_tokens_for(%Auth.Provider{} = provider, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do
|
||||
Token.Query.not_deleted()
|
||||
|> Token.Query.by_provider_id(provider.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> delete_tokens()
|
||||
|> soft_delete_tokens()
|
||||
end
|
||||
end
|
||||
|
||||
def delete_tokens_for(%Relays.Group{} = group, %Auth.Subject{} = subject) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB
|
||||
def soft_delete_tokens_for(%Relays.Group{} = group, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do
|
||||
Token.Query.not_deleted()
|
||||
|> Token.Query.by_relay_group_id(group.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> delete_tokens()
|
||||
|> soft_delete_tokens()
|
||||
end
|
||||
end
|
||||
|
||||
def delete_tokens_for(%Gateways.Group{} = group, %Auth.Subject{} = subject) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB
|
||||
def soft_delete_tokens_for(%Gateways.Group{} = group, %Auth.Subject{} = subject) do
|
||||
with :ok <- Auth.ensure_has_permissions(subject, Authorizer.manage_tokens_permission()) do
|
||||
Token.Query.not_deleted()
|
||||
|> Token.Query.by_gateway_group_id(group.id)
|
||||
|> Authorizer.for_subject(subject)
|
||||
|> delete_tokens()
|
||||
|> soft_delete_tokens()
|
||||
end
|
||||
end
|
||||
|
||||
def delete_all_tokens_by_type_and_assoc(:email, %Auth.Identity{} = identity) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB
|
||||
def soft_delete_all_tokens_by_type_and_assoc(:email, %Auth.Identity{} = identity) do
|
||||
Token.Query.not_deleted()
|
||||
|> Token.Query.by_type(:email)
|
||||
|> Token.Query.by_account_id(identity.account_id)
|
||||
|> Token.Query.by_identity_id(identity.id)
|
||||
|> delete_tokens()
|
||||
|> soft_delete_tokens()
|
||||
end
|
||||
|
||||
def delete_expired_tokens do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB
|
||||
def soft_delete_expired_tokens do
|
||||
Token.Query.not_deleted()
|
||||
|> Token.Query.expired()
|
||||
|> delete_tokens()
|
||||
|> soft_delete_tokens()
|
||||
end
|
||||
|
||||
defp delete_tokens(queryable) do
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is remove from DB
|
||||
defp soft_delete_tokens(queryable) do
|
||||
{_count, tokens} =
|
||||
queryable
|
||||
|> Token.Query.delete()
|
||||
|
||||
@@ -30,6 +30,22 @@ defmodule Domain.Tokens.Authorizer do
|
||||
[]
|
||||
end
|
||||
|
||||
def ensure_has_access_to(%Token{} = token, %Subject{} = subject) do
|
||||
cond do
|
||||
# If token belongs to same actor, check own permission
|
||||
subject.account.id == token.account_id and owns_token?(token, subject) ->
|
||||
Domain.Auth.ensure_has_permissions(subject, manage_own_tokens_permission())
|
||||
|
||||
# Otherwise, check global manage permission
|
||||
subject.account.id == token.account_id ->
|
||||
Domain.Auth.ensure_has_permissions(subject, manage_tokens_permission())
|
||||
|
||||
# Different account
|
||||
true ->
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def for_subject(queryable, %Subject{} = subject) do
|
||||
cond do
|
||||
@@ -42,4 +58,8 @@ defmodule Domain.Tokens.Authorizer do
|
||||
|> Token.Query.by_actor_id(subject.actor.id)
|
||||
end
|
||||
end
|
||||
|
||||
defp owns_token?(token, subject) do
|
||||
token.actor_id == subject.actor.id
|
||||
end
|
||||
end
|
||||
|
||||
@@ -48,9 +48,9 @@ defmodule Domain.Tokens.Token do
|
||||
field :created_by_user_agent, :string
|
||||
field :created_by_remote_ip, Domain.Types.IP
|
||||
|
||||
has_many :clients, Domain.Clients.Client, foreign_key: :last_used_token_id
|
||||
|
||||
field :expires_at, :utc_datetime_usec
|
||||
|
||||
# TODO: HARD-DELETE - Remove field after soft deletion is removed
|
||||
field :deleted_at, :utc_datetime_usec
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@@ -125,6 +125,7 @@ defmodule Domain.Tokens.Token.Changeset do
|
||||
|> validate_required(~w[last_seen_user_agent last_seen_remote_ip]a)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` is removed from DB
|
||||
def delete(%Token{} = token) do
|
||||
token
|
||||
|> change()
|
||||
|
||||
@@ -5,6 +5,7 @@ defmodule Domain.Tokens.Token.Query do
|
||||
from(tokens in Domain.Tokens.Token, as: :tokens)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def not_deleted do
|
||||
all()
|
||||
|> where([tokens: tokens], is_nil(tokens.deleted_at))
|
||||
@@ -78,6 +79,7 @@ defmodule Domain.Tokens.Token.Query do
|
||||
where(queryable, [tokens: tokens], tokens.gateway_group_id == ^gateway_group_id)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after `deleted_at` column is removed from DB
|
||||
def delete(queryable) do
|
||||
queryable
|
||||
|> Ecto.Query.select([tokens: tokens], tokens)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
defmodule Domain.Repo.Migrations.DropLastUsedTokenIdFromGateways do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:gateways) do
|
||||
remove(:last_used_token_id, references(:tokens, type: :binary_id, on_delete: :nilify_all))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
defmodule Domain.Repo.Migrations.DropLastUsedTokenIdFromRelays do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:relays) do
|
||||
remove(:last_used_token_id, references(:tokens, type: :binary_id, on_delete: :nilify_all))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,9 @@
|
||||
defmodule Domain.Repo.Migrations.DropLastUsedTokenIdFromClients do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
alter table(:clients) do
|
||||
remove(:last_used_token_id, references(:tokens, type: :binary_id, on_delete: :nilify_all))
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -687,7 +687,6 @@ defmodule Domain.Repo.Seeds do
|
||||
{:ok, global_relay} =
|
||||
Relays.upsert_relay(
|
||||
global_relay_group,
|
||||
global_relay_group_token,
|
||||
%{
|
||||
ipv4: {189, 172, 72, 111},
|
||||
ipv6: {0, 0, 0, 0, 0, 0, 0, 1}
|
||||
@@ -699,7 +698,6 @@ defmodule Domain.Repo.Seeds do
|
||||
{:ok, _global_relay} =
|
||||
Relays.upsert_relay(
|
||||
global_relay_group,
|
||||
global_relay_group_token,
|
||||
%{
|
||||
ipv4: {189, 172, 72, 111 + i},
|
||||
ipv6: {0, 0, 0, 0, 0, 0, 0, i}
|
||||
@@ -744,7 +742,6 @@ defmodule Domain.Repo.Seeds do
|
||||
{:ok, relay} =
|
||||
Relays.upsert_relay(
|
||||
relay_group,
|
||||
relay_group_token,
|
||||
%{
|
||||
ipv4: {189, 172, 73, 111},
|
||||
ipv6: {0, 0, 0, 0, 0, 0, 0, 1}
|
||||
@@ -760,7 +757,6 @@ defmodule Domain.Repo.Seeds do
|
||||
{:ok, _relay} =
|
||||
Relays.upsert_relay(
|
||||
relay_group,
|
||||
relay_group_token,
|
||||
%{
|
||||
ipv4: {189, 172, 73, 111 + i},
|
||||
ipv6: {0, 0, 0, 0, 0, 0, 0, i}
|
||||
@@ -815,7 +811,6 @@ defmodule Domain.Repo.Seeds do
|
||||
{:ok, gateway1} =
|
||||
Gateways.upsert_gateway(
|
||||
gateway_group,
|
||||
gateway_group_token,
|
||||
%{
|
||||
external_id: Ecto.UUID.generate(),
|
||||
name: "gw-#{Domain.Crypto.random_token(5, encoder: :user_friendly)}",
|
||||
@@ -831,7 +826,6 @@ defmodule Domain.Repo.Seeds do
|
||||
{:ok, gateway2} =
|
||||
Gateways.upsert_gateway(
|
||||
gateway_group,
|
||||
gateway_group_token,
|
||||
%{
|
||||
external_id: Ecto.UUID.generate(),
|
||||
name: "gw-#{Domain.Crypto.random_token(5, encoder: :user_friendly)}",
|
||||
@@ -848,7 +842,6 @@ defmodule Domain.Repo.Seeds do
|
||||
{:ok, _gateway} =
|
||||
Gateways.upsert_gateway(
|
||||
gateway_group,
|
||||
gateway_group_token,
|
||||
%{
|
||||
external_id: Ecto.UUID.generate(),
|
||||
name: "gw-#{Domain.Crypto.random_token(5, encoder: :user_friendly)}",
|
||||
|
||||
@@ -84,17 +84,18 @@ defmodule Domain.ActorsTest do
|
||||
assert fetch_group_by_id(group.id, subject) == {:error, :not_found}
|
||||
end
|
||||
|
||||
test "returns deleted groups", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
group =
|
||||
Fixtures.Actors.create_group(account: account)
|
||||
|> Fixtures.Actors.delete_group()
|
||||
# TODO: HARD-DELETE - This test is no longer relevant
|
||||
# test "returns deleted groups", %{
|
||||
# account: account,
|
||||
# subject: subject
|
||||
# } do
|
||||
# group =
|
||||
# Fixtures.Actors.create_group(account: account)
|
||||
# |> Fixtures.Actors.delete_group()
|
||||
|
||||
assert {:ok, fetched_group} = fetch_group_by_id(group.id, subject)
|
||||
assert fetched_group.id == group.id
|
||||
end
|
||||
# assert {:ok, fetched_group} = fetch_group_by_id(group.id, subject)
|
||||
# assert fetched_group.id == group.id
|
||||
# end
|
||||
|
||||
test "returns group by id", %{account: account, subject: subject} do
|
||||
group = Fixtures.Actors.create_group(account: account)
|
||||
@@ -155,6 +156,7 @@ defmodule Domain.ActorsTest do
|
||||
assert {:ok, [], _metadata} = list_groups(subject)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Is this test needed any more?
|
||||
test "does not list deleted groups", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
@@ -216,6 +218,7 @@ defmodule Domain.ActorsTest do
|
||||
assert {:ok, [], _metadata} = list_editable_groups(subject)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Is this test needed any more?
|
||||
test "does not list deleted groups", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
@@ -288,6 +291,7 @@ defmodule Domain.ActorsTest do
|
||||
assert {:ok, [], _metadata} = list_groups_for(actor, subject)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Is this test needed any more?
|
||||
test "does not list deleted groups", %{account: account, actor: actor, subject: subject} do
|
||||
group = Fixtures.Actors.create_group(account: account)
|
||||
Fixtures.Actors.create_membership(account: account, actor: actor, group: group)
|
||||
@@ -383,23 +387,6 @@ defmodule Domain.ActorsTest do
|
||||
assert length(peek[group.id].items) == 1
|
||||
end
|
||||
|
||||
test "ignores deleted actors", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
group = Fixtures.Actors.create_group(account: account)
|
||||
actor = Fixtures.Actors.create_actor(account: account) |> Fixtures.Actors.delete()
|
||||
Fixtures.Actors.create_membership(account: account, group: group, actor: actor)
|
||||
Fixtures.Actors.create_membership(account: account, group: group)
|
||||
Fixtures.Actors.create_membership(account: account, group: group)
|
||||
Fixtures.Actors.create_membership(account: account, group: group)
|
||||
Fixtures.Actors.create_membership(account: account, group: group)
|
||||
|
||||
assert {:ok, peek} = peek_group_actors([group], 3, subject)
|
||||
assert peek[group.id].count == 4
|
||||
assert length(peek[group.id].items) == 3
|
||||
end
|
||||
|
||||
test "ignores other groups", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
@@ -520,20 +507,6 @@ defmodule Domain.ActorsTest do
|
||||
assert length(peek[actor.id].items) == 1
|
||||
end
|
||||
|
||||
test "ignores deleted groups", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
actor = Fixtures.Actors.create_actor(account: account)
|
||||
group = Fixtures.Actors.create_group(account: account) |> Fixtures.Actors.delete()
|
||||
Fixtures.Actors.create_membership(account: account, group: group, actor: actor)
|
||||
Fixtures.Actors.create_membership(account: account, group: group)
|
||||
|
||||
assert {:ok, peek} = peek_actor_groups([actor], 3, subject)
|
||||
assert peek[actor.id].count == 0
|
||||
assert Enum.empty?(peek[actor.id].items)
|
||||
end
|
||||
|
||||
test "ignores other groups", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
@@ -630,8 +603,19 @@ defmodule Domain.ActorsTest do
|
||||
subject: subject
|
||||
} do
|
||||
actor = Fixtures.Actors.create_actor(account: account)
|
||||
client = Fixtures.Clients.create_client(account: account, actor: actor)
|
||||
Clients.Presence.connect(client)
|
||||
actor_identity = Fixtures.Auth.create_identity(account: account, actor: actor)
|
||||
|
||||
client =
|
||||
Fixtures.Clients.create_client(account: account, actor: actor, identity: actor_identity)
|
||||
|
||||
client_token =
|
||||
Fixtures.Tokens.create_client_token(
|
||||
account: account,
|
||||
actor: actor,
|
||||
identity: actor_identity
|
||||
)
|
||||
|
||||
Clients.Presence.connect(client, client_token.id)
|
||||
|
||||
assert {:ok, peek} = peek_actor_clients([actor], 3, subject)
|
||||
assert [%Clients.Client{} = client] = peek[actor.id].items
|
||||
@@ -654,20 +638,6 @@ defmodule Domain.ActorsTest do
|
||||
assert Enum.count(peek) == 1
|
||||
end
|
||||
|
||||
test "ignores deleted clients", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
actor = Fixtures.Actors.create_actor(account: account)
|
||||
|
||||
Fixtures.Clients.create_client(account: account, actor: actor)
|
||||
|> Fixtures.Clients.delete_client()
|
||||
|
||||
assert {:ok, peek} = peek_actor_clients([actor], 3, subject)
|
||||
assert peek[actor.id].count == 0
|
||||
assert Enum.empty?(peek[actor.id].items)
|
||||
end
|
||||
|
||||
test "ignores other clients", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
@@ -825,7 +795,7 @@ defmodule Domain.ActorsTest do
|
||||
provider_identifier: "G:GROUP_ID1"
|
||||
)
|
||||
|
||||
_group2 =
|
||||
group2 =
|
||||
Fixtures.Actors.create_group(
|
||||
account: account,
|
||||
provider: provider,
|
||||
@@ -862,6 +832,8 @@ defmodule Domain.ActorsTest do
|
||||
%{"name" => "Group:Finance", "provider_identifier" => "G:GROUP_ID4"}
|
||||
]
|
||||
|
||||
deleted_group_ids = [group1.provider_identifier, group2.provider_identifier]
|
||||
|
||||
assert {:ok,
|
||||
%{
|
||||
groups: [_group1, _group2, _group3, _group4, _group5],
|
||||
@@ -872,10 +844,9 @@ defmodule Domain.ActorsTest do
|
||||
}} = sync_provider_groups(provider, attrs_list)
|
||||
|
||||
assert Enum.all?(["G:GROUP_ID1", "OU:OU_ID1"], &(&1 in delete))
|
||||
assert deleted_group1.provider_identifier in ["G:GROUP_ID1", "OU:OU_ID1"]
|
||||
assert deleted_group2.provider_identifier in ["G:GROUP_ID1", "OU:OU_ID1"]
|
||||
assert Repo.aggregate(Actors.Group, :count) == 5
|
||||
assert Repo.aggregate(Actors.Group.Query.not_deleted(), :count) == 3
|
||||
assert deleted_group1 in deleted_group_ids
|
||||
assert deleted_group2 in deleted_group_ids
|
||||
assert Repo.aggregate(Actors.Group, :count) == 3
|
||||
|
||||
assert Map.keys(group_ids_by_provider_identifier) |> length() == 3
|
||||
end
|
||||
@@ -959,50 +930,52 @@ defmodule Domain.ActorsTest do
|
||||
}}
|
||||
end
|
||||
|
||||
test "ignores synced groups that are soft deleted", %{
|
||||
account: account,
|
||||
provider: provider
|
||||
} do
|
||||
deleted_group =
|
||||
Fixtures.Actors.create_group(
|
||||
account: account,
|
||||
provider: provider,
|
||||
provider_identifier: "G:GROUP_ID1",
|
||||
name: "ALREADY_DELETED"
|
||||
)
|
||||
# TODO: HARD-DELETE - This test is no longer relevant
|
||||
|
||||
Domain.Actors.Group.Query.not_deleted()
|
||||
|> Domain.Actors.Group.Query.by_account_id(account.id)
|
||||
|> Domain.Actors.Group.Query.by_provider_id(provider.id)
|
||||
|> Domain.Actors.Group.Query.by_provider_identifier(
|
||||
{:in, [deleted_group.provider_identifier]}
|
||||
)
|
||||
|> Domain.Actors.delete_groups()
|
||||
# test "ignores synced groups that are soft deleted", %{
|
||||
# account: account,
|
||||
# provider: provider
|
||||
# } do
|
||||
# deleted_group =
|
||||
# Fixtures.Actors.create_group(
|
||||
# account: account,
|
||||
# provider: provider,
|
||||
# provider_identifier: "G:GROUP_ID1",
|
||||
# name: "ALREADY_DELETED"
|
||||
# )
|
||||
|
||||
group2 =
|
||||
Fixtures.Actors.create_group(
|
||||
account: account,
|
||||
provider: provider,
|
||||
provider_identifier: "G:GROUP_ID2",
|
||||
name: "TO_BE_UPDATED"
|
||||
)
|
||||
# Domain.Actors.Group.Query.not_deleted()
|
||||
# |> Domain.Actors.Group.Query.by_account_id(account.id)
|
||||
# |> Domain.Actors.Group.Query.by_provider_id(provider.id)
|
||||
# |> Domain.Actors.Group.Query.by_provider_identifier(
|
||||
# {:in, [deleted_group.provider_identifier]}
|
||||
# )
|
||||
# |> Domain.Actors.delete_groups()
|
||||
|
||||
attrs_list = [
|
||||
%{"name" => "Group:Infrastructure", "provider_identifier" => "G:GROUP_ID2"},
|
||||
%{"name" => "Group:Security", "provider_identifier" => "G:GROUP_ID3"},
|
||||
%{"name" => "Group:Finance", "provider_identifier" => "G:GROUP_ID4"}
|
||||
]
|
||||
# group2 =
|
||||
# Fixtures.Actors.create_group(
|
||||
# account: account,
|
||||
# provider: provider,
|
||||
# provider_identifier: "G:GROUP_ID2",
|
||||
# name: "TO_BE_UPDATED"
|
||||
# )
|
||||
|
||||
provider_identifiers = Enum.map(attrs_list, & &1["provider_identifier"])
|
||||
# attrs_list = [
|
||||
# %{"name" => "Group:Infrastructure", "provider_identifier" => "G:GROUP_ID2"},
|
||||
# %{"name" => "Group:Security", "provider_identifier" => "G:GROUP_ID3"},
|
||||
# %{"name" => "Group:Finance", "provider_identifier" => "G:GROUP_ID4"}
|
||||
# ]
|
||||
|
||||
assert {:ok, sync_data} = sync_provider_groups(provider, attrs_list)
|
||||
# provider_identifiers = Enum.map(attrs_list, & &1["provider_identifier"])
|
||||
|
||||
assert Enum.sort(Enum.map(sync_data.groups, & &1.name)) ==
|
||||
Enum.sort([deleted_group.name, group2.name])
|
||||
# assert {:ok, sync_data} = sync_provider_groups(provider, attrs_list)
|
||||
|
||||
assert sync_data.deleted == []
|
||||
assert sync_data.plan == {provider_identifiers, []}
|
||||
end
|
||||
# assert Enum.sort(Enum.map(sync_data.groups, & &1.name)) ==
|
||||
# Enum.sort([deleted_group.name, group2.name])
|
||||
|
||||
# assert sync_data.deleted == []
|
||||
# assert sync_data.plan == {provider_identifiers, []}
|
||||
# end
|
||||
end
|
||||
|
||||
describe "sync_provider_memberships/2" do
|
||||
@@ -1809,6 +1782,7 @@ defmodule Domain.ActorsTest do
|
||||
assert membership.actor_id == actor.id
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Is this test needed any more?
|
||||
test "removes memberships when managed group is deleted", %{
|
||||
account: account,
|
||||
actor: actor,
|
||||
@@ -1997,19 +1971,25 @@ defmodule Domain.ActorsTest do
|
||||
}
|
||||
end
|
||||
|
||||
test "returns error on state conflict", %{account: account, subject: subject} do
|
||||
test "raises error when deleting stale group structs", %{account: account, subject: subject} do
|
||||
group = Fixtures.Actors.create_group(account: account)
|
||||
|
||||
assert {:ok, deleted} = delete_group(group, subject)
|
||||
assert delete_group(deleted, subject) == {:error, :not_found}
|
||||
assert delete_group(group, subject) == {:error, :not_found}
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_group(deleted, subject)
|
||||
end
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_group(group, subject)
|
||||
end
|
||||
end
|
||||
|
||||
test "deletes groups", %{account: account, subject: subject} do
|
||||
group = Fixtures.Actors.create_group(account: account)
|
||||
|
||||
assert {:ok, deleted} = delete_group(group, subject)
|
||||
assert deleted.deleted_at
|
||||
assert {:ok, _deleted} = delete_group(group, subject)
|
||||
refute Repo.get(Domain.Actors.Group, group.id)
|
||||
end
|
||||
|
||||
test "deletes group memberships", %{account: account, subject: subject} do
|
||||
@@ -2021,7 +2001,8 @@ defmodule Domain.ActorsTest do
|
||||
assert Repo.aggregate(Actors.Membership, :count) == 0
|
||||
end
|
||||
|
||||
test "deletes policies that use this group", %{
|
||||
# TODO: HARD-DELETE - Should this test be put in policies?
|
||||
test "cascade deletes policies that use this group", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
@@ -2030,10 +2011,10 @@ defmodule Domain.ActorsTest do
|
||||
policy = Fixtures.Policies.create_policy(account: account, actor_group: group)
|
||||
other_policy = Fixtures.Policies.create_policy(account: account)
|
||||
|
||||
assert {:ok, _resource} = delete_group(group, subject)
|
||||
assert {:ok, _group} = delete_group(group, subject)
|
||||
|
||||
refute is_nil(Repo.get_by(Domain.Policies.Policy, id: policy.id).deleted_at)
|
||||
assert is_nil(Repo.get_by(Domain.Policies.Policy, id: other_policy.id).deleted_at)
|
||||
refute Repo.get_by(Domain.Policies.Policy, id: policy.id)
|
||||
assert Repo.get_by(Domain.Policies.Policy, id: other_policy.id)
|
||||
end
|
||||
|
||||
test "returns error when subject has no permission to delete groups", %{
|
||||
@@ -2043,11 +2024,7 @@ defmodule Domain.ActorsTest do
|
||||
|
||||
subject = Fixtures.Auth.remove_permissions(subject)
|
||||
|
||||
assert delete_group(group, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Actors.Authorizer.manage_actors_permission()]}}
|
||||
assert delete_group(group, subject) == {:error, :unauthorized}
|
||||
end
|
||||
|
||||
test "raises if group is synced", %{
|
||||
@@ -2061,7 +2038,7 @@ defmodule Domain.ActorsTest do
|
||||
end
|
||||
end
|
||||
|
||||
describe "delete_groups_for/2" do
|
||||
describe "cascade delete on groups" do
|
||||
setup do
|
||||
account = Fixtures.Accounts.create_account()
|
||||
actor = Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
|
||||
@@ -2079,68 +2056,20 @@ defmodule Domain.ActorsTest do
|
||||
}
|
||||
end
|
||||
|
||||
test "does nothing on state conflict", %{
|
||||
# TODO: HARD-DELETE - Is this test needed any more?
|
||||
test "delete groups when provider is deleted", %{
|
||||
account: account,
|
||||
provider: provider,
|
||||
subject: subject
|
||||
} do
|
||||
Fixtures.Actors.create_group(account: account, provider: provider)
|
||||
group1 = Fixtures.Actors.create_group(account: account, provider: provider)
|
||||
group2 = Fixtures.Actors.create_group(account: account, provider: provider)
|
||||
|
||||
assert {:ok, [_deleted]} = delete_groups_for(provider, subject)
|
||||
assert delete_groups_for(provider, subject) == {:ok, []}
|
||||
assert delete_groups_for(provider, subject) == {:ok, []}
|
||||
end
|
||||
assert {:ok, _provider} = Auth.delete_provider(provider, subject)
|
||||
|
||||
test "deletes provider groups", %{account: account, provider: provider, subject: subject} do
|
||||
group = Fixtures.Actors.create_group(account: account, provider: provider)
|
||||
|
||||
assert {:ok, [deleted]} = delete_groups_for(provider, subject)
|
||||
assert deleted.deleted_at
|
||||
|
||||
refute is_nil(Repo.get(Actors.Group, group.id).deleted_at)
|
||||
end
|
||||
|
||||
test "deletes provider group memberships", %{
|
||||
account: account,
|
||||
provider: provider,
|
||||
subject: subject
|
||||
} do
|
||||
actor = Fixtures.Actors.create_actor(account: account)
|
||||
group = Fixtures.Actors.create_group(account: account, provider: provider)
|
||||
Fixtures.Actors.create_membership(account: account, actor: actor, group: group)
|
||||
|
||||
assert {:ok, _deleted} = delete_groups_for(provider, subject)
|
||||
|
||||
refute Repo.get_by(Actors.Membership, group_id: group.id)
|
||||
end
|
||||
|
||||
test "deletes policies that use deleted groups", %{
|
||||
account: account,
|
||||
provider: provider,
|
||||
subject: subject
|
||||
} do
|
||||
group = Fixtures.Actors.create_group(account: account, provider: provider)
|
||||
|
||||
policy = Fixtures.Policies.create_policy(account: account, actor_group: group)
|
||||
other_policy = Fixtures.Policies.create_policy(account: account)
|
||||
|
||||
assert {:ok, _resource} = delete_groups_for(provider, subject)
|
||||
|
||||
refute is_nil(Repo.get_by(Domain.Policies.Policy, id: policy.id).deleted_at)
|
||||
assert is_nil(Repo.get_by(Domain.Policies.Policy, id: other_policy.id).deleted_at)
|
||||
end
|
||||
|
||||
test "returns error when subject has no permission to delete groups", %{
|
||||
provider: provider,
|
||||
subject: subject
|
||||
} do
|
||||
subject = Fixtures.Auth.remove_permissions(subject)
|
||||
|
||||
assert delete_groups_for(provider, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Actors.Authorizer.manage_actors_permission()]}}
|
||||
refute Repo.get(Domain.Auth.Provider, provider.id)
|
||||
refute Repo.get(Actors.Group, group1.id)
|
||||
refute Repo.get(Actors.Group, group2.id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2191,16 +2120,20 @@ defmodule Domain.ActorsTest do
|
||||
end
|
||||
end
|
||||
|
||||
describe "group_deleted?/1" do
|
||||
test "returns true for deleted groups" do
|
||||
# TODO: HARD-DELETE - Remove after soft delete functionality is gone
|
||||
describe "group_soft_deleted?/1" do
|
||||
test "returns true for soft deleted groups" do
|
||||
account = Fixtures.Accounts.create_account()
|
||||
group = Fixtures.Actors.create_group(account: account) |> Fixtures.Actors.delete_group()
|
||||
assert group_deleted?(group) == true
|
||||
|
||||
group =
|
||||
Fixtures.Actors.create_group(account: account) |> Fixtures.Actors.soft_delete_group()
|
||||
|
||||
assert group_soft_deleted?(group) == true
|
||||
end
|
||||
|
||||
test "returns false for manually created groups" do
|
||||
group = Fixtures.Actors.create_group()
|
||||
assert group_deleted?(group) == false
|
||||
assert group_soft_deleted?(group) == false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2228,15 +2161,6 @@ defmodule Domain.ActorsTest do
|
||||
|
||||
assert count_users_for_account(account) == 0
|
||||
end
|
||||
|
||||
test "does not count deleted" do
|
||||
account = Fixtures.Accounts.create_account()
|
||||
|
||||
Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
|
||||
|> Fixtures.Actors.delete()
|
||||
|
||||
assert count_users_for_account(account) == 0
|
||||
end
|
||||
end
|
||||
|
||||
describe "count_account_admin_users_for_account/1" do
|
||||
@@ -2270,15 +2194,6 @@ defmodule Domain.ActorsTest do
|
||||
|
||||
assert count_account_admin_users_for_account(account) == 0
|
||||
end
|
||||
|
||||
test "does not count deleted account admin actors" do
|
||||
account = Fixtures.Accounts.create_account()
|
||||
|
||||
Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
|
||||
|> Fixtures.Actors.delete()
|
||||
|
||||
assert count_account_admin_users_for_account(account) == 0
|
||||
end
|
||||
end
|
||||
|
||||
describe "count_service_accounts_for_account/1" do
|
||||
@@ -2990,9 +2905,7 @@ defmodule Domain.ActorsTest do
|
||||
subject = Fixtures.Auth.create_subject(identity: identity)
|
||||
|
||||
assert {:ok, _actor} = disable_actor(actor, subject)
|
||||
|
||||
assert token = Repo.get(Domain.Tokens.Token, subject.token_id)
|
||||
assert token.deleted_at
|
||||
refute Repo.get(Domain.Tokens.Token, subject.token_id)
|
||||
end
|
||||
|
||||
test "returns error when trying to disable the last admin actor" do
|
||||
@@ -3146,13 +3059,9 @@ defmodule Domain.ActorsTest do
|
||||
other_actor = Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
|
||||
|
||||
assert {:ok, actor} = delete_actor(actor, subject)
|
||||
assert actor.deleted_at
|
||||
refute Repo.get(Actors.Actor, actor.id)
|
||||
|
||||
assert actor = Repo.get(Actors.Actor, actor.id)
|
||||
assert actor.deleted_at
|
||||
|
||||
assert other_actor = Repo.get(Actors.Actor, other_actor.id)
|
||||
assert is_nil(other_actor.deleted_at)
|
||||
assert Repo.get(Actors.Actor, other_actor.id)
|
||||
end
|
||||
|
||||
test "updates managed group memberships", %{account: account, actor: actor, subject: subject} do
|
||||
@@ -3161,13 +3070,14 @@ defmodule Domain.ActorsTest do
|
||||
group = Fixtures.Actors.create_managed_group(account: account)
|
||||
|
||||
assert {:ok, actor} = delete_actor(actor, subject)
|
||||
assert actor.deleted_at
|
||||
refute Repo.get(Domain.Actors.Actor, actor.id)
|
||||
|
||||
group = Repo.preload(group, :memberships, force: true)
|
||||
assert [membership] = group.memberships
|
||||
assert membership.actor_id == new_actor.id
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Move this test to Tokens since it has the FK constraint
|
||||
test "deletes token", %{
|
||||
account: account,
|
||||
actor: actor,
|
||||
@@ -3176,24 +3086,22 @@ defmodule Domain.ActorsTest do
|
||||
Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
|
||||
|
||||
assert {:ok, _actor} = delete_actor(actor, subject)
|
||||
|
||||
assert token = Repo.get(Domain.Tokens.Token, subject.token_id)
|
||||
assert token.deleted_at
|
||||
refute Repo.get(Domain.Tokens.Token, subject.token_id)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Move this test to AuthIdentities since it has the FK constraint
|
||||
test "deletes actor identities", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
actor_to_delete = Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
|
||||
Fixtures.Auth.create_identity(account: account, actor: actor_to_delete)
|
||||
identity = Fixtures.Auth.create_identity(account: account, actor: actor_to_delete)
|
||||
|
||||
assert {:ok, actor} = delete_actor(actor_to_delete, subject)
|
||||
assert actor.deleted_at
|
||||
|
||||
assert Repo.aggregate(Domain.Auth.Identity.Query.not_deleted(), :count) == 1
|
||||
assert {:ok, _actor} = delete_actor(actor_to_delete, subject)
|
||||
refute Repo.get(Domain.Auth.Identity, identity.id)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Move this test to Clients since it has the FK constraint
|
||||
test "deletes actor clients", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
@@ -3201,8 +3109,7 @@ defmodule Domain.ActorsTest do
|
||||
actor_to_delete = Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
|
||||
Fixtures.Clients.create_client(account: account, actor: actor_to_delete)
|
||||
|
||||
assert {:ok, actor} = delete_actor(actor_to_delete, subject)
|
||||
assert actor.deleted_at
|
||||
assert {:ok, _actor} = delete_actor(actor_to_delete, subject)
|
||||
|
||||
assert Repo.aggregate(Domain.Clients.Client.Query.not_deleted(), :count) == 0
|
||||
end
|
||||
@@ -3260,69 +3167,70 @@ defmodule Domain.ActorsTest do
|
||||
assert delete_actor(actor, subject) == {:error, :cant_delete_the_last_admin}
|
||||
|
||||
assert {:ok, service_account_actor} = delete_actor(service_account_actor, subject)
|
||||
assert service_account_actor.deleted_at
|
||||
refute Repo.get(Domain.Actors.Actor, service_account_actor.id)
|
||||
end
|
||||
|
||||
test "returns error when trying to delete the last admin actor using a race condition" do
|
||||
for _ <- 0..50 do
|
||||
test_pid = self()
|
||||
# TODO: HARD-DELETE - Need to figure out if we care about this case
|
||||
# test "returns error when trying to delete the last admin actor using a race condition" do
|
||||
# for _ <- 0..50 do
|
||||
# test_pid = self()
|
||||
|
||||
Task.async(fn ->
|
||||
allow_child_sandbox_access(test_pid)
|
||||
# Task.async(fn ->
|
||||
# allow_child_sandbox_access(test_pid)
|
||||
|
||||
Domain.Config.put_env_override(:outbound_email_adapter_configured?, true)
|
||||
# Domain.Config.put_env_override(:outbound_email_adapter_configured?, true)
|
||||
|
||||
account = Fixtures.Accounts.create_account()
|
||||
provider = Fixtures.Auth.create_email_provider(account: account)
|
||||
# account = Fixtures.Accounts.create_account()
|
||||
# provider = Fixtures.Auth.create_email_provider(account: account)
|
||||
|
||||
actor_one =
|
||||
Fixtures.Actors.create_actor(
|
||||
type: :account_admin_user,
|
||||
account: account,
|
||||
provider: provider
|
||||
)
|
||||
# actor_one =
|
||||
# Fixtures.Actors.create_actor(
|
||||
# type: :account_admin_user,
|
||||
# account: account,
|
||||
# provider: provider
|
||||
# )
|
||||
|
||||
actor_two =
|
||||
Fixtures.Actors.create_actor(
|
||||
type: :account_admin_user,
|
||||
account: account,
|
||||
provider: provider
|
||||
)
|
||||
# actor_two =
|
||||
# Fixtures.Actors.create_actor(
|
||||
# type: :account_admin_user,
|
||||
# account: account,
|
||||
# provider: provider
|
||||
# )
|
||||
|
||||
identity_one =
|
||||
Fixtures.Auth.create_identity(
|
||||
account: account,
|
||||
actor: actor_one,
|
||||
provider: provider
|
||||
)
|
||||
# identity_one =
|
||||
# Fixtures.Auth.create_identity(
|
||||
# account: account,
|
||||
# actor: actor_one,
|
||||
# provider: provider
|
||||
# )
|
||||
|
||||
identity_two =
|
||||
Fixtures.Auth.create_identity(
|
||||
account: account,
|
||||
actor: actor_two,
|
||||
provider: provider
|
||||
)
|
||||
# identity_two =
|
||||
# Fixtures.Auth.create_identity(
|
||||
# account: account,
|
||||
# actor: actor_two,
|
||||
# provider: provider
|
||||
# )
|
||||
|
||||
subject_one = Fixtures.Auth.create_subject(identity: identity_one)
|
||||
subject_two = Fixtures.Auth.create_subject(identity: identity_two)
|
||||
# subject_one = Fixtures.Auth.create_subject(identity: identity_one)
|
||||
# subject_two = Fixtures.Auth.create_subject(identity: identity_two)
|
||||
|
||||
for {actor, subject} <- [{actor_two, subject_one}, {actor_one, subject_two}] do
|
||||
Task.async(fn ->
|
||||
allow_child_sandbox_access(test_pid)
|
||||
delete_actor(actor, subject)
|
||||
end)
|
||||
end
|
||||
|> Task.await_many()
|
||||
# for {actor, subject} <- [{actor_two, subject_one}, {actor_one, subject_two}] do
|
||||
# Task.async(fn ->
|
||||
# allow_child_sandbox_access(test_pid)
|
||||
# delete_actor(actor, subject)
|
||||
# end)
|
||||
# end
|
||||
# |> Task.await_many()
|
||||
|
||||
queryable =
|
||||
Actors.Actor.Query.not_deleted()
|
||||
|> Actors.Actor.Query.by_account_id(account.id)
|
||||
# queryable =
|
||||
# Actors.Actor.Query.not_deleted()
|
||||
# |> Actors.Actor.Query.by_account_id(account.id)
|
||||
|
||||
assert Repo.aggregate(queryable, :count) == 1
|
||||
end)
|
||||
end
|
||||
|> Task.await_many()
|
||||
end
|
||||
# assert Repo.aggregate(queryable, :count) == 1
|
||||
# end)
|
||||
# end
|
||||
# |> Task.await_many()
|
||||
# end
|
||||
|
||||
test "does not allow to delete an actor twice", %{
|
||||
account: account,
|
||||
@@ -3331,7 +3239,10 @@ defmodule Domain.ActorsTest do
|
||||
other_actor = Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
|
||||
|
||||
assert {:ok, _actor} = delete_actor(other_actor, subject)
|
||||
assert delete_actor(other_actor, subject) == {:error, :not_found}
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_actor(other_actor, subject)
|
||||
end
|
||||
end
|
||||
|
||||
test "does not allow to delete actors in other accounts", %{
|
||||
@@ -3339,7 +3250,7 @@ defmodule Domain.ActorsTest do
|
||||
} do
|
||||
other_actor = Fixtures.Actors.create_actor(type: :account_admin_user)
|
||||
|
||||
assert delete_actor(other_actor, subject) == {:error, :not_found}
|
||||
assert delete_actor(other_actor, subject) == {:error, :unauthorized}
|
||||
end
|
||||
|
||||
test "returns error when subject cannot delete actors" do
|
||||
@@ -3353,8 +3264,12 @@ defmodule Domain.ActorsTest do
|
||||
assert delete_actor(actor, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Actors.Authorizer.manage_actors_permission()]}}
|
||||
[
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [
|
||||
%Domain.Auth.Permission{resource: Domain.Actors.Actor, action: :manage}
|
||||
]
|
||||
]}}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3446,11 +3361,12 @@ defmodule Domain.ActorsTest do
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - Remove after soft deletion functionality is removed
|
||||
describe "actor_deleted?/1" do
|
||||
test "returns true when actor is deleted" do
|
||||
test "returns true when actor is soft deleted" do
|
||||
actor =
|
||||
Fixtures.Actors.create_actor()
|
||||
|> Fixtures.Actors.delete()
|
||||
|> Fixtures.Actors.soft_delete()
|
||||
|
||||
assert actor_deleted?(actor) == true
|
||||
end
|
||||
@@ -3478,10 +3394,11 @@ defmodule Domain.ActorsTest do
|
||||
end
|
||||
end
|
||||
|
||||
defp allow_child_sandbox_access(parent_pid) do
|
||||
Ecto.Adapters.SQL.Sandbox.allow(Repo, parent_pid, self())
|
||||
# Allow is async call we need to break current process execution
|
||||
# to allow sandbox to be enabled
|
||||
:timer.sleep(10)
|
||||
end
|
||||
# TODO: HARD-DELETE - This may not be needed anymore
|
||||
# defp allow_child_sandbox_access(parent_pid) do
|
||||
# Ecto.Adapters.SQL.Sandbox.allow(Repo, parent_pid, self())
|
||||
# # Allow is async call we need to break current process execution
|
||||
# # to allow sandbox to be enabled
|
||||
# :timer.sleep(10)
|
||||
# end
|
||||
end
|
||||
|
||||
@@ -133,8 +133,8 @@ defmodule Domain.Auth.Adapters.EmailTest do
|
||||
"request_sequence_number" => 2
|
||||
} = identity.provider_state
|
||||
|
||||
assert Repo.get(Domain.Tokens.Token, first_token_id).deleted_at
|
||||
refute Repo.get(Domain.Tokens.Token, second_token_id).deleted_at
|
||||
refute Repo.get(Domain.Tokens.Token, first_token_id)
|
||||
assert Repo.get(Domain.Tokens.Token, second_token_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -175,14 +175,11 @@ defmodule Domain.Auth.Adapters.EmailTest do
|
||||
|
||||
assert {:ok, identity, nil} = verify_secret(identity, context, token)
|
||||
|
||||
assert %{last_used_token_id: token_id} = identity.provider_state
|
||||
assert identity.provider_state == %{}
|
||||
assert identity.provider_virtual_state == %{}
|
||||
|
||||
token = Repo.get(Domain.Tokens.Token, token_id)
|
||||
assert token.deleted_at
|
||||
|
||||
token = Repo.get(Domain.Tokens.Token, other_token.id)
|
||||
assert token.deleted_at
|
||||
# Email verification tokens are cleaned up automatically
|
||||
refute Repo.get(Domain.Tokens.Token, other_token.id)
|
||||
end
|
||||
|
||||
test "returns error when token belongs to a different identity", %{
|
||||
|
||||
@@ -677,8 +677,7 @@ defmodule Domain.Auth.Adapters.GoogleWorkspace.Jobs.SyncDirectoryTest do
|
||||
)
|
||||
|
||||
# Signs out users which identity has been deleted
|
||||
deleted_identity_token = Repo.reload(deleted_identity_token)
|
||||
assert deleted_identity_token.deleted_at
|
||||
refute Repo.reload(deleted_identity_token)
|
||||
end
|
||||
|
||||
test "resurrects deleted identities that reappear on the next sync", %{
|
||||
|
||||
@@ -440,8 +440,7 @@ defmodule Domain.Auth.Adapters.JumpCloud.Jobs.SyncDirectoryTest do
|
||||
refute Repo.get_by(Domain.Actors.Membership, group_id: deleted_group.id)
|
||||
|
||||
# Signs out users which identity has been deleted
|
||||
deleted_identity_token = Repo.reload(deleted_identity_token)
|
||||
assert deleted_identity_token.deleted_at
|
||||
refute Repo.reload(deleted_identity_token)
|
||||
end
|
||||
|
||||
test "resurrects deleted identities that reappear on the next sync", %{
|
||||
|
||||
@@ -508,8 +508,7 @@ defmodule Domain.Auth.Adapters.MicrosoftEntra.Jobs.SyncDirectoryTest do
|
||||
)
|
||||
|
||||
# Signs out users which identity has been deleted
|
||||
deleted_identity_token = Repo.reload(deleted_identity_token)
|
||||
assert deleted_identity_token.deleted_at
|
||||
refute Repo.reload(deleted_identity_token)
|
||||
end
|
||||
|
||||
test "stops the sync retries on 401 error on the provider", %{
|
||||
|
||||
@@ -742,8 +742,7 @@ defmodule Domain.Auth.Adapters.Okta.Jobs.SyncDirectoryTest do
|
||||
)
|
||||
|
||||
# Signs out users which identity has been deleted
|
||||
deleted_identity_token = Repo.reload(deleted_identity_token)
|
||||
assert deleted_identity_token.deleted_at
|
||||
refute Repo.reload(deleted_identity_token)
|
||||
end
|
||||
|
||||
test "resurrects deleted identities that reappear on the next sync", %{
|
||||
|
||||
@@ -56,12 +56,11 @@ defmodule Domain.AuthTest do
|
||||
assert fetch_provider_by_id("foo", subject) == {:error, :not_found}
|
||||
end
|
||||
|
||||
test "returns deleted provider", %{account: account, subject: subject} do
|
||||
test "does not return deleted provider", %{account: account, subject: subject} do
|
||||
provider = Fixtures.Auth.create_userpass_provider(account: account)
|
||||
{:ok, _provider} = delete_provider(provider, subject)
|
||||
|
||||
assert {:ok, fetched_provider} = fetch_provider_by_id(provider.id, subject)
|
||||
assert fetched_provider.id == provider.id
|
||||
assert {:error, :not_found} = fetch_provider_by_id(provider.id, subject)
|
||||
end
|
||||
|
||||
test "does not return provider from other accounts", %{subject: subject} do
|
||||
@@ -1032,7 +1031,8 @@ defmodule Domain.AuthTest do
|
||||
assert is_nil(other_provider.disabled_at)
|
||||
end
|
||||
|
||||
test "deletes tokens issues for provider identities", %{
|
||||
# TODO: HARD-DELETE - This test should be moved to Tokens since it has the FK
|
||||
test "deletes tokens issued for provider identities", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
@@ -1050,8 +1050,7 @@ defmodule Domain.AuthTest do
|
||||
|
||||
assert {:ok, _provider} = disable_provider(provider, subject)
|
||||
|
||||
assert token = Repo.get(Tokens.Token, token.id)
|
||||
assert token.deleted_at
|
||||
refute Repo.get(Tokens.Token, token.id)
|
||||
end
|
||||
|
||||
test "returns error when trying to disable the last provider", %{
|
||||
@@ -1207,10 +1206,8 @@ defmodule Domain.AuthTest do
|
||||
other_provider = Fixtures.Auth.create_userpass_provider(account: account)
|
||||
|
||||
assert {:ok, provider} = delete_provider(provider, subject)
|
||||
assert provider.deleted_at
|
||||
|
||||
assert provider = Repo.get(Auth.Provider, provider.id)
|
||||
assert provider.deleted_at
|
||||
refute Repo.get(Auth.Provider, provider.id)
|
||||
|
||||
assert other_provider = Repo.get(Auth.Provider, other_provider.id)
|
||||
assert is_nil(other_provider.deleted_at)
|
||||
@@ -1234,11 +1231,8 @@ defmodule Domain.AuthTest do
|
||||
|
||||
assert {:ok, _provider} = delete_provider(provider, subject)
|
||||
|
||||
assert identity = Repo.get(Auth.Identity, identity.id)
|
||||
assert identity.deleted_at
|
||||
|
||||
assert token = Repo.get(Tokens.Token, token.id)
|
||||
assert token.deleted_at
|
||||
refute Repo.get(Auth.Identity, identity.id)
|
||||
refute Repo.get(Tokens.Token, token.id)
|
||||
end
|
||||
|
||||
test "deletes provider actor groups", %{
|
||||
@@ -1250,8 +1244,7 @@ defmodule Domain.AuthTest do
|
||||
|
||||
assert {:ok, _provider} = delete_provider(provider, subject)
|
||||
|
||||
assert actor_group = Repo.get(Domain.Actors.Group, actor_group.id)
|
||||
assert actor_group.deleted_at
|
||||
refute Repo.get(Domain.Actors.Group, actor_group.id)
|
||||
end
|
||||
|
||||
test "returns error when trying to delete the last provider", %{
|
||||
@@ -1281,65 +1274,73 @@ defmodule Domain.AuthTest do
|
||||
assert delete_provider(provider, subject) == {:error, :cant_delete_the_last_provider}
|
||||
end
|
||||
|
||||
test "returns error when trying to delete the last provider using a race condition" do
|
||||
for _ <- 0..50 do
|
||||
test_pid = self()
|
||||
# TODO: HARD-DELETE - Need to figure out if we care about this case
|
||||
# test "returns error when trying to delete the last provider using a race condition" do
|
||||
# for _ <- 0..50 do
|
||||
# test_pid = self()
|
||||
|
||||
Task.async(fn ->
|
||||
allow_child_sandbox_access(test_pid)
|
||||
# Task.async(fn ->
|
||||
# allow_child_sandbox_access(test_pid)
|
||||
|
||||
account = Fixtures.Accounts.create_account()
|
||||
# account = Fixtures.Accounts.create_account()
|
||||
|
||||
provider_one = Fixtures.Auth.create_email_provider(account: account)
|
||||
provider_two = Fixtures.Auth.create_userpass_provider(account: account)
|
||||
# provider_one = Fixtures.Auth.create_email_provider(account: account)
|
||||
# provider_two = Fixtures.Auth.create_userpass_provider(account: account)
|
||||
|
||||
actor =
|
||||
Fixtures.Actors.create_actor(
|
||||
type: :account_admin_user,
|
||||
account: account,
|
||||
provider: provider_one
|
||||
)
|
||||
# actor =
|
||||
# Fixtures.Actors.create_actor(
|
||||
# type: :account_admin_user,
|
||||
# account: account,
|
||||
# provider: provider_one
|
||||
# )
|
||||
|
||||
identity =
|
||||
Fixtures.Auth.create_identity(
|
||||
account: account,
|
||||
actor: actor,
|
||||
provider: provider_one
|
||||
)
|
||||
# identity =
|
||||
# Fixtures.Auth.create_identity(
|
||||
# account: account,
|
||||
# actor: actor,
|
||||
# provider: provider_one
|
||||
# )
|
||||
|
||||
subject = Fixtures.Auth.create_subject(identity: identity)
|
||||
# subject = Fixtures.Auth.create_subject(identity: identity)
|
||||
|
||||
for provider <- [provider_two, provider_one] do
|
||||
Task.async(fn ->
|
||||
allow_child_sandbox_access(test_pid)
|
||||
delete_provider(provider, subject)
|
||||
end)
|
||||
end
|
||||
|> Task.await_many()
|
||||
# for provider <- [provider_two, provider_one] do
|
||||
# Task.async(fn ->
|
||||
# allow_child_sandbox_access(test_pid)
|
||||
# delete_provider(provider, subject)
|
||||
# end)
|
||||
# end
|
||||
# |> Task.await_many()
|
||||
|
||||
assert Auth.Provider.Query.not_deleted()
|
||||
|> Auth.Provider.Query.by_account_id(account.id)
|
||||
|> Repo.aggregate(:count) == 1
|
||||
end)
|
||||
end
|
||||
|> Task.await_many()
|
||||
end
|
||||
# assert Auth.Provider.Query.not_deleted()
|
||||
# |> Auth.Provider.Query.by_account_id(account.id)
|
||||
# |> Repo.aggregate(:count) == 1
|
||||
# end)
|
||||
# end
|
||||
# |> Task.await_many()
|
||||
# end
|
||||
|
||||
test "returns error when provider is already deleted", %{
|
||||
test "raises error when deleting stale provider structs", %{
|
||||
subject: subject,
|
||||
account: account
|
||||
} do
|
||||
provider = Fixtures.Auth.create_userpass_provider(account: account)
|
||||
assert {:ok, deleted_provider} = delete_provider(provider, subject)
|
||||
assert delete_provider(provider, subject) == {:error, :not_found}
|
||||
assert delete_provider(deleted_provider, subject) == {:error, :not_found}
|
||||
|
||||
assert_raise(Ecto.StaleEntryError, fn ->
|
||||
delete_provider(provider, subject)
|
||||
end)
|
||||
|
||||
assert_raise(Ecto.StaleEntryError, fn ->
|
||||
delete_provider(deleted_provider, subject)
|
||||
end)
|
||||
end
|
||||
|
||||
test "does not allow to delete providers in other accounts", %{
|
||||
subject: subject
|
||||
} do
|
||||
provider = Fixtures.Auth.create_userpass_provider()
|
||||
assert delete_provider(provider, subject) == {:error, :not_found}
|
||||
|
||||
assert delete_provider(provider, subject) == {:error, :unauthorized}
|
||||
end
|
||||
|
||||
test "returns error when subject cannot delete providers", %{
|
||||
@@ -1351,8 +1352,12 @@ defmodule Domain.AuthTest do
|
||||
assert delete_provider(provider, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Authorizer.manage_providers_permission()]}}
|
||||
[
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [
|
||||
%Domain.Auth.Permission{resource: Domain.Auth.Provider, action: :manage}
|
||||
]
|
||||
]}}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1650,7 +1655,7 @@ defmodule Domain.AuthTest do
|
||||
plan: {insert, [], []},
|
||||
inserted: [_actor1, _actor2],
|
||||
updated: [],
|
||||
deleted: [],
|
||||
deleted: 0,
|
||||
actor_ids_by_provider_identifier: actor_ids_by_provider_identifier
|
||||
}} = sync_provider_identities(provider, attrs_list)
|
||||
|
||||
@@ -1712,7 +1717,7 @@ defmodule Domain.AuthTest do
|
||||
%{
|
||||
identities: [_identity1, _identity2],
|
||||
plan: {[], update, []},
|
||||
deleted: [],
|
||||
deleted: 0,
|
||||
updated: [_updated_identity1, _updated_identity2],
|
||||
inserted: [],
|
||||
actor_ids_by_provider_identifier: actor_ids_by_provider_identifier
|
||||
@@ -1762,7 +1767,7 @@ defmodule Domain.AuthTest do
|
||||
%{
|
||||
identities: [fetched_identity],
|
||||
plan: {[], ["USER_ID1"], []},
|
||||
deleted: [],
|
||||
deleted: 0,
|
||||
inserted: [],
|
||||
actor_ids_by_provider_identifier: actor_ids_by_provider_identifier
|
||||
}} = sync_provider_identities(provider, attrs_list)
|
||||
@@ -1797,7 +1802,7 @@ defmodule Domain.AuthTest do
|
||||
%{
|
||||
identities: [fetched_identity],
|
||||
plan: {[], [], []},
|
||||
deleted: [],
|
||||
deleted: 0,
|
||||
inserted: [],
|
||||
actor_ids_by_provider_identifier: %{}
|
||||
}} = sync_provider_identities(provider, attrs_list)
|
||||
@@ -1808,91 +1813,88 @@ defmodule Domain.AuthTest do
|
||||
assert identity.deleted_at
|
||||
end
|
||||
|
||||
test "deletes removed identities", %{account: account, provider: provider} do
|
||||
provider_identifiers = ["USER_ID1", "USER_ID2", "USER_ID3", "USER_ID4", "USER_ID5"]
|
||||
# TODO: HARD-DELETE - Need to figure out if the flows message checking is necessary
|
||||
# test "deletes removed identities", %{account: account, provider: provider} do
|
||||
# provider_identifiers = ["USER_ID1", "USER_ID2", "USER_ID3", "USER_ID4", "USER_ID5"]
|
||||
|
||||
deleted_identity_actor = Fixtures.Actors.create_actor(account: account)
|
||||
# deleted_identity_actor = Fixtures.Actors.create_actor(account: account)
|
||||
|
||||
deleted_identity =
|
||||
Fixtures.Auth.create_identity(
|
||||
account: account,
|
||||
provider: provider,
|
||||
actor: deleted_identity_actor,
|
||||
provider_identifier: Enum.at(provider_identifiers, 0)
|
||||
)
|
||||
# deleted_identity =
|
||||
# Fixtures.Auth.create_identity(
|
||||
# account: account,
|
||||
# provider: provider,
|
||||
# actor: deleted_identity_actor,
|
||||
# provider_identifier: Enum.at(provider_identifiers, 0)
|
||||
# )
|
||||
|
||||
deleted_identity_token =
|
||||
Fixtures.Tokens.create_token(
|
||||
account: account,
|
||||
actor: deleted_identity_actor,
|
||||
identity: deleted_identity
|
||||
)
|
||||
# deleted_identity_token =
|
||||
# Fixtures.Tokens.create_token(
|
||||
# account: account,
|
||||
# actor: deleted_identity_actor,
|
||||
# identity: deleted_identity
|
||||
# )
|
||||
|
||||
for n <- 1..4 do
|
||||
Fixtures.Auth.create_identity(
|
||||
account: account,
|
||||
provider: provider,
|
||||
provider_identifier: Enum.at(provider_identifiers, n)
|
||||
)
|
||||
end
|
||||
# for n <- 1..4 do
|
||||
# Fixtures.Auth.create_identity(
|
||||
# account: account,
|
||||
# provider: provider,
|
||||
# provider_identifier: Enum.at(provider_identifiers, n)
|
||||
# )
|
||||
# end
|
||||
|
||||
attrs_list = [
|
||||
%{
|
||||
"actor" => %{
|
||||
"name" => "Joe Smith",
|
||||
"type" => "account_user"
|
||||
},
|
||||
"provider_identifier" => "USER_ID3"
|
||||
},
|
||||
%{
|
||||
"actor" => %{
|
||||
"name" => "Jennie Smith",
|
||||
"type" => "account_user"
|
||||
},
|
||||
"provider_identifier" => "USER_ID4"
|
||||
},
|
||||
%{
|
||||
"actor" => %{
|
||||
"name" => "Jane Doe",
|
||||
"type" => "account_admin_user"
|
||||
},
|
||||
"provider_identifier" => "USER_ID5"
|
||||
}
|
||||
]
|
||||
# attrs_list = [
|
||||
# %{
|
||||
# "actor" => %{
|
||||
# "name" => "Joe Smith",
|
||||
# "type" => "account_user"
|
||||
# },
|
||||
# "provider_identifier" => "USER_ID3"
|
||||
# },
|
||||
# %{
|
||||
# "actor" => %{
|
||||
# "name" => "Jennie Smith",
|
||||
# "type" => "account_user"
|
||||
# },
|
||||
# "provider_identifier" => "USER_ID4"
|
||||
# },
|
||||
# %{
|
||||
# "actor" => %{
|
||||
# "name" => "Jane Doe",
|
||||
# "type" => "account_admin_user"
|
||||
# },
|
||||
# "provider_identifier" => "USER_ID5"
|
||||
# }
|
||||
# ]
|
||||
|
||||
assert {:ok,
|
||||
%{
|
||||
identities: [_id1, _id2, _id3, _id4, _id5],
|
||||
plan: {[], upsert, delete},
|
||||
deleted: [deleted_identity1, deleted_identity2],
|
||||
inserted: [],
|
||||
actor_ids_by_provider_identifier: actor_ids_by_provider_identifier
|
||||
}} = sync_provider_identities(provider, attrs_list)
|
||||
# assert {:ok,
|
||||
# %{
|
||||
# identities: [_id1, _id2, _id3, _id4, _id5],
|
||||
# plan: {[], upsert, delete},
|
||||
# deleted: 2,
|
||||
# inserted: [],
|
||||
# actor_ids_by_provider_identifier: actor_ids_by_provider_identifier
|
||||
# }} = sync_provider_identities(provider, attrs_list)
|
||||
|
||||
assert Enum.sort(upsert) == ["USER_ID3", "USER_ID4", "USER_ID5"]
|
||||
# assert Enum.sort(upsert) == ["USER_ID3", "USER_ID4", "USER_ID5"]
|
||||
|
||||
assert Enum.take(provider_identifiers, 2)
|
||||
|> Enum.all?(&(&1 in delete))
|
||||
# assert Enum.take(provider_identifiers, 2)
|
||||
# |> Enum.all?(&(&1 in delete))
|
||||
|
||||
assert deleted_identity1.provider_identifier in delete
|
||||
assert deleted_identity2.provider_identifier in delete
|
||||
# refute Repo.get_by(Auth.Identity, provider_identifier: "USER_ID1")
|
||||
# refute Repo.get_by(Auth.Identity, provider_identifier: "USER_ID2")
|
||||
|
||||
assert Auth.Identity.Query.all()
|
||||
|> Auth.Identity.Query.by_provider_id(provider.id)
|
||||
|> Repo.aggregate(:count) == 5
|
||||
# assert Auth.Identity.Query.all()
|
||||
# |> Auth.Identity.Query.by_provider_id(provider.id)
|
||||
# |> Repo.aggregate(:count) == 3
|
||||
|
||||
assert Auth.Identity.Query.not_deleted()
|
||||
|> Auth.Identity.Query.by_provider_id(provider.id)
|
||||
|> Repo.aggregate(:count) == 3
|
||||
# assert actor_ids_by_provider_identifier
|
||||
# |> Map.keys()
|
||||
# |> length() == 3
|
||||
|
||||
assert actor_ids_by_provider_identifier
|
||||
|> Map.keys()
|
||||
|> length() == 3
|
||||
|
||||
# Signs out users which identity has been deleted
|
||||
deleted_identity_token = Repo.reload(deleted_identity_token)
|
||||
assert deleted_identity_token.deleted_at
|
||||
end
|
||||
# # Signs out users which identity has been deleted
|
||||
# deleted_identity_token = Repo.reload(deleted_identity_token)
|
||||
# assert deleted_identity_token.deleted_at
|
||||
# end
|
||||
|
||||
test "circuit breaker prevents mass deletions of identities", %{
|
||||
account: account,
|
||||
@@ -1947,7 +1949,7 @@ defmodule Domain.AuthTest do
|
||||
%{
|
||||
identities: [],
|
||||
plan: {[], [], []},
|
||||
deleted: [],
|
||||
deleted: 0,
|
||||
updated: [],
|
||||
inserted: [],
|
||||
actor_ids_by_provider_identifier: %{}
|
||||
@@ -2012,7 +2014,7 @@ defmodule Domain.AuthTest do
|
||||
%{
|
||||
identities: [_identity1, _identity2],
|
||||
plan: {[], update, []},
|
||||
deleted: [],
|
||||
deleted: 0,
|
||||
inserted: [],
|
||||
actor_ids_by_provider_identifier: actor_ids_by_provider_identifier
|
||||
}} = sync_provider_identities(provider, attrs_list)
|
||||
@@ -2532,16 +2534,16 @@ defmodule Domain.AuthTest do
|
||||
assert {:ok, deleted_identity} = delete_identity(identity, subject)
|
||||
|
||||
assert deleted_identity.id == identity.id
|
||||
assert deleted_identity.deleted_at
|
||||
|
||||
assert Repo.get(Auth.Identity, identity.id).deleted_at
|
||||
refute Repo.get(Auth.Identity, identity.id)
|
||||
end
|
||||
|
||||
test "deletes identity that belongs to another actor with manage permission", %{
|
||||
account: account,
|
||||
provider: provider,
|
||||
subject: subject
|
||||
} do
|
||||
test "allows subject to delete identity that belongs to another actor with manage permission",
|
||||
%{
|
||||
account: account,
|
||||
provider: provider,
|
||||
subject: subject
|
||||
} do
|
||||
identity = Fixtures.Auth.create_identity(account: account, provider: provider)
|
||||
|
||||
subject =
|
||||
@@ -2555,11 +2557,11 @@ defmodule Domain.AuthTest do
|
||||
assert {:ok, deleted_identity} = delete_identity(identity, subject)
|
||||
|
||||
assert deleted_identity.id == identity.id
|
||||
assert deleted_identity.deleted_at
|
||||
|
||||
assert Repo.get(Auth.Identity, identity.id).deleted_at
|
||||
refute Repo.get(Auth.Identity, identity.id)
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - This test should be moved to tokens since it has the FK
|
||||
test "deletes token", %{
|
||||
account: account,
|
||||
provider: provider,
|
||||
@@ -2570,21 +2572,29 @@ defmodule Domain.AuthTest do
|
||||
|
||||
assert {:ok, _deleted_identity} = delete_identity(identity, subject)
|
||||
|
||||
assert token = Repo.get(Domain.Tokens.Token, token.id)
|
||||
assert token.deleted_at
|
||||
refute Repo.get(Domain.Tokens.Token, token.id)
|
||||
end
|
||||
|
||||
test "does not delete identity that belongs to another actor with manage_own permission", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
identity = Fixtures.Auth.create_identity()
|
||||
identity = Fixtures.Auth.create_identity(account: account)
|
||||
|
||||
subject =
|
||||
subject
|
||||
|> Fixtures.Auth.remove_permissions()
|
||||
|> Fixtures.Auth.add_permission(Authorizer.manage_own_identities_permission())
|
||||
|
||||
assert delete_identity(identity, subject) == {:error, :not_found}
|
||||
assert delete_identity(identity, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
[
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [
|
||||
%Domain.Auth.Permission{resource: Domain.Auth.Identity, action: :manage}
|
||||
]
|
||||
]}}
|
||||
end
|
||||
|
||||
test "does not delete identity that belongs to another actor with just view permission", %{
|
||||
@@ -2597,10 +2607,10 @@ defmodule Domain.AuthTest do
|
||||
|> Fixtures.Auth.remove_permissions()
|
||||
|> Fixtures.Auth.add_permission(Authorizer.manage_own_identities_permission())
|
||||
|
||||
assert delete_identity(identity, subject) == {:error, :not_found}
|
||||
assert delete_identity(identity, subject) == {:error, :unauthorized}
|
||||
end
|
||||
|
||||
test "returns error when identity does not exist", %{
|
||||
test "raises error when deleting stale identity structs", %{
|
||||
account: account,
|
||||
provider: provider,
|
||||
actor: actor,
|
||||
@@ -2609,7 +2619,10 @@ defmodule Domain.AuthTest do
|
||||
identity = Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor)
|
||||
|
||||
assert {:ok, _identity} = delete_identity(identity, subject)
|
||||
assert delete_identity(identity, subject) == {:error, :not_found}
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_identity(identity, subject)
|
||||
end
|
||||
end
|
||||
|
||||
test "returns error when subject cannot delete identities", %{subject: subject} do
|
||||
@@ -2617,17 +2630,7 @@ defmodule Domain.AuthTest do
|
||||
|
||||
subject = Fixtures.Auth.remove_permissions(subject)
|
||||
|
||||
assert delete_identity(identity, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [
|
||||
{:one_of,
|
||||
[
|
||||
Authorizer.manage_identities_permission(),
|
||||
Authorizer.manage_own_identities_permission()
|
||||
]}
|
||||
]}}
|
||||
assert delete_identity(identity, subject) == {:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -2656,7 +2659,7 @@ defmodule Domain.AuthTest do
|
||||
}
|
||||
end
|
||||
|
||||
test "removes all identities and flows that belong to an actor", %{
|
||||
test "removes all identities that belong to an actor", %{
|
||||
account: account,
|
||||
provider: provider,
|
||||
subject: subject
|
||||
@@ -2668,12 +2671,12 @@ defmodule Domain.AuthTest do
|
||||
|
||||
all_identities_query = Auth.Identity.Query.all()
|
||||
assert Repo.aggregate(all_identities_query, :count) == 4
|
||||
assert delete_identities_for(actor, subject) == :ok
|
||||
assert delete_identities_for(actor, subject) == {:ok, 3}
|
||||
|
||||
assert Repo.aggregate(all_identities_query, :count) == 4
|
||||
assert Repo.aggregate(all_identities_query, :count) == 1
|
||||
|
||||
by_actor_id_query =
|
||||
Auth.Identity.Query.not_deleted()
|
||||
Auth.Identity.Query.all()
|
||||
|> Auth.Identity.Query.by_actor_id(actor.id)
|
||||
|
||||
assert Repo.aggregate(by_actor_id_query, :count) == 0
|
||||
@@ -2691,9 +2694,9 @@ defmodule Domain.AuthTest do
|
||||
|
||||
all_identities_query = Auth.Identity.Query.all()
|
||||
assert Repo.aggregate(all_identities_query, :count) == 4
|
||||
assert delete_identities_for(provider, subject) == :ok
|
||||
assert {:ok, 4} = delete_identities_for(provider, subject)
|
||||
|
||||
assert Repo.aggregate(all_identities_query, :count) == 4
|
||||
assert Repo.aggregate(all_identities_query, :count) == 0
|
||||
|
||||
by_provider_id_query =
|
||||
Auth.Identity.Query.not_deleted()
|
||||
@@ -2711,10 +2714,9 @@ defmodule Domain.AuthTest do
|
||||
identity = Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor)
|
||||
token = Fixtures.Tokens.create_token(account: account, identity: identity)
|
||||
|
||||
assert delete_identities_for(actor, subject) == :ok
|
||||
assert delete_identities_for(actor, subject) == {:ok, 1}
|
||||
|
||||
assert token = Repo.get(Domain.Tokens.Token, token.id)
|
||||
assert token.deleted_at
|
||||
refute Repo.get(Domain.Tokens.Token, token.id)
|
||||
end
|
||||
|
||||
test "does not remove identities that belong to another actor", %{
|
||||
@@ -2724,7 +2726,8 @@ defmodule Domain.AuthTest do
|
||||
} do
|
||||
actor = Fixtures.Actors.create_actor(account: account, provider: provider)
|
||||
Fixtures.Auth.create_identity(account: account, provider: provider)
|
||||
assert delete_identities_for(actor, subject) == :ok
|
||||
|
||||
assert delete_identities_for(actor, subject) == {:ok, 0}
|
||||
assert Repo.aggregate(Auth.Identity.Query.all(), :count) == 2
|
||||
end
|
||||
|
||||
@@ -2750,18 +2753,19 @@ defmodule Domain.AuthTest do
|
||||
end
|
||||
end
|
||||
|
||||
describe "identity_deleted?/1" do
|
||||
# TODO: HARD-DELETE - Remove or update after soft deletion is removed
|
||||
describe "identity_soft_deleted?/1" do
|
||||
test "returns true when identity is deleted" do
|
||||
identity =
|
||||
Fixtures.Auth.create_identity()
|
||||
|> Fixtures.Auth.delete_identity()
|
||||
|
||||
assert identity_deleted?(identity) == true
|
||||
assert identity_soft_deleted?(identity) == true
|
||||
end
|
||||
|
||||
test "returns false when identity is not deleted" do
|
||||
identity = Fixtures.Auth.create_identity()
|
||||
assert identity_deleted?(identity) == false
|
||||
assert identity_soft_deleted?(identity) == false
|
||||
end
|
||||
end
|
||||
|
||||
@@ -3104,48 +3108,50 @@ defmodule Domain.AuthTest do
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
|
||||
test "returns error when actor is deleted", %{
|
||||
account: account,
|
||||
provider: provider,
|
||||
user_agent: user_agent,
|
||||
remote_ip: remote_ip
|
||||
} do
|
||||
nonce = "test_nonce_for_firezone"
|
||||
# TODO: HARD-DELETE - Not sure this test is needed any more. I don't think this is a reachable state.
|
||||
# test "returns error when actor is deleted", %{
|
||||
# account: account,
|
||||
# provider: provider,
|
||||
# user_agent: user_agent,
|
||||
# remote_ip: remote_ip
|
||||
# } do
|
||||
# nonce = "test_nonce_for_firezone"
|
||||
|
||||
actor =
|
||||
Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
|
||||
|> Fixtures.Actors.delete()
|
||||
# actor =
|
||||
# Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
|
||||
# |> Fixtures.Actors.delete()
|
||||
|
||||
identity = Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor)
|
||||
context = %Auth.Context{type: :browser, user_agent: user_agent, remote_ip: remote_ip}
|
||||
{:ok, identity} = Domain.Auth.Adapters.Email.request_sign_in_token(identity, context)
|
||||
# identity = Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor)
|
||||
# context = %Auth.Context{type: :browser, user_agent: user_agent, remote_ip: remote_ip}
|
||||
# {:ok, identity} = Domain.Auth.Adapters.Email.request_sign_in_token(identity, context)
|
||||
|
||||
secret = identity.provider_virtual_state.nonce <> identity.provider_virtual_state.fragment
|
||||
# secret = identity.provider_virtual_state.nonce <> identity.provider_virtual_state.fragment
|
||||
|
||||
assert sign_in(provider, identity.provider_identifier, nonce, secret, context) ==
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
# assert sign_in(provider, identity.provider_identifier, nonce, secret, context) ==
|
||||
# {:error, :unauthorized}
|
||||
# end
|
||||
|
||||
test "returns error when provider is deleted", %{
|
||||
account: account,
|
||||
provider: provider,
|
||||
user_agent: user_agent,
|
||||
remote_ip: remote_ip
|
||||
} do
|
||||
nonce = "test_nonce_for_firezone"
|
||||
# TODO: HARD-DELETE - Not sure this test is needed any more. I don't think this is a reachable state.
|
||||
# test "returns error when provider is deleted", %{
|
||||
# account: account,
|
||||
# provider: provider,
|
||||
# user_agent: user_agent,
|
||||
# remote_ip: remote_ip
|
||||
# } do
|
||||
# nonce = "test_nonce_for_firezone"
|
||||
|
||||
actor = Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
|
||||
identity = Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor)
|
||||
subject = Fixtures.Auth.create_subject(identity: identity)
|
||||
{:ok, _provider} = delete_provider(provider, subject)
|
||||
# actor = Fixtures.Actors.create_actor(type: :account_admin_user, account: account)
|
||||
# identity = Fixtures.Auth.create_identity(account: account, provider: provider, actor: actor)
|
||||
# subject = Fixtures.Auth.create_subject(identity: identity)
|
||||
# {:ok, _provider} = delete_provider(provider, subject)
|
||||
|
||||
context = %Auth.Context{type: :browser, user_agent: user_agent, remote_ip: remote_ip}
|
||||
{:ok, identity} = Domain.Auth.Adapters.Email.request_sign_in_token(identity, context)
|
||||
secret = identity.provider_virtual_state.nonce <> identity.provider_virtual_state.fragment
|
||||
# context = %Auth.Context{type: :browser, user_agent: user_agent, remote_ip: remote_ip}
|
||||
# {:ok, identity} = Domain.Auth.Adapters.Email.request_sign_in_token(identity, context)
|
||||
# secret = identity.provider_virtual_state.nonce <> identity.provider_virtual_state.fragment
|
||||
|
||||
assert sign_in(provider, identity.provider_identifier, nonce, secret, context) ==
|
||||
{:error, :unauthorized}
|
||||
end
|
||||
# assert sign_in(provider, identity.provider_identifier, nonce, secret, context) ==
|
||||
# {:error, :unauthorized}
|
||||
# end
|
||||
end
|
||||
|
||||
describe "sign_in/3" do
|
||||
@@ -3606,7 +3612,7 @@ defmodule Domain.AuthTest do
|
||||
assert redirect_url =~ "client_id=#{provider.adapter_config["client_id"]}"
|
||||
assert redirect_url =~ "post_logout_redirect_uri=#{post_redirect_url}"
|
||||
|
||||
assert Repo.get(Tokens.Token, subject.token_id).deleted_at
|
||||
refute Repo.get(Tokens.Token, subject.token_id)
|
||||
end
|
||||
|
||||
test "returns identity and url without changes for other providers" do
|
||||
@@ -3619,7 +3625,7 @@ defmodule Domain.AuthTest do
|
||||
assert {:ok, %Auth.Identity{}, "https://fz.d/sign_out"} =
|
||||
sign_out(subject, "https://fz.d/sign_out")
|
||||
|
||||
assert Repo.get(Tokens.Token, subject.token_id).deleted_at
|
||||
refute Repo.get(Tokens.Token, subject.token_id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4321,10 +4327,11 @@ defmodule Domain.AuthTest do
|
||||
end
|
||||
end
|
||||
|
||||
defp allow_child_sandbox_access(parent_pid) do
|
||||
Ecto.Adapters.SQL.Sandbox.allow(Repo, parent_pid, self())
|
||||
# Allow is async call we need to break current process execution
|
||||
# to allow sandbox to be enabled
|
||||
:timer.sleep(10)
|
||||
end
|
||||
# TODO: HARD-DELETE - This may not be needed anymore
|
||||
# defp allow_child_sandbox_access(parent_pid) do
|
||||
# Ecto.Adapters.SQL.Sandbox.allow(Repo, parent_pid, self())
|
||||
# # Allow is async call we need to break current process execution
|
||||
# # to allow sandbox to be enabled
|
||||
# :timer.sleep(10)
|
||||
# end
|
||||
end
|
||||
|
||||
@@ -95,7 +95,7 @@ defmodule Domain.ClientsTest do
|
||||
assert fetch_client_by_id("foo", subject) == {:error, :not_found}
|
||||
end
|
||||
|
||||
test "returns deleted clients", %{
|
||||
test "does not return deleted clients", %{
|
||||
unprivileged_actor: actor,
|
||||
unprivileged_subject: subject
|
||||
} do
|
||||
@@ -103,7 +103,7 @@ defmodule Domain.ClientsTest do
|
||||
Fixtures.Clients.create_client(actor: actor)
|
||||
|> Fixtures.Clients.delete_client()
|
||||
|
||||
assert {:ok, _client} = fetch_client_by_id(client.id, subject)
|
||||
assert {:error, :not_found} = fetch_client_by_id(client.id, subject)
|
||||
end
|
||||
|
||||
test "returns client by id", %{unprivileged_actor: actor, unprivileged_subject: subject} do
|
||||
@@ -114,14 +114,21 @@ defmodule Domain.ClientsTest do
|
||||
{:ok, client}
|
||||
end
|
||||
|
||||
test "preloads online status", %{unprivileged_actor: actor, unprivileged_subject: subject} do
|
||||
client = Fixtures.Clients.create_client(actor: actor)
|
||||
test "preloads online status", %{account: account, unprivileged_subject: subject} do
|
||||
client = Fixtures.Clients.create_client(actor: subject.actor)
|
||||
|
||||
client_token =
|
||||
Fixtures.Tokens.create_client_token(
|
||||
account: account,
|
||||
actor: subject.actor,
|
||||
identity: subject.identity
|
||||
)
|
||||
|
||||
assert {:ok, client} = fetch_client_by_id(client.id, subject, preload: [:online?])
|
||||
assert client.online? == false
|
||||
|
||||
{:ok, _} = Clients.Presence.Account.track(client.account_id, client.id)
|
||||
{:ok, _} = Clients.Presence.Actor.track(client.actor_id, client.id)
|
||||
{:ok, _} = Clients.Presence.Actor.track(client.actor_id, client.id, client_token.id)
|
||||
|
||||
assert {:ok, client} = fetch_client_by_id(client.id, subject, preload: [:online?])
|
||||
assert client.online? == true
|
||||
@@ -222,14 +229,21 @@ defmodule Domain.ClientsTest do
|
||||
assert fetch_client_by_id!(client.id, preload: [:online?, :identity]) == client
|
||||
end
|
||||
|
||||
test "preloads online status", %{unprivileged_actor: actor} do
|
||||
client = Fixtures.Clients.create_client(actor: actor)
|
||||
test "preloads online status", %{account: account, unprivileged_subject: subject} do
|
||||
client = Fixtures.Clients.create_client(actor: subject.actor)
|
||||
|
||||
client_token =
|
||||
Fixtures.Tokens.create_client_token(
|
||||
account: account,
|
||||
actor: subject.actor,
|
||||
identity: subject.identity
|
||||
)
|
||||
|
||||
assert client = fetch_client_by_id!(client.id, preload: [:online?])
|
||||
assert client.online? == false
|
||||
|
||||
{:ok, _} = Clients.Presence.Account.track(client.account_id, client.id)
|
||||
{:ok, _} = Clients.Presence.Actor.track(client.actor_id, client.id)
|
||||
{:ok, _} = Clients.Presence.Actor.track(client.actor_id, client.id, client_token.id)
|
||||
|
||||
assert client = fetch_client_by_id!(client.id, preload: [:online?])
|
||||
assert client.online? == true
|
||||
@@ -283,14 +297,21 @@ defmodule Domain.ClientsTest do
|
||||
assert length(clients) == 2
|
||||
end
|
||||
|
||||
test "preloads online status", %{unprivileged_actor: actor, unprivileged_subject: subject} do
|
||||
Fixtures.Clients.create_client(actor: actor)
|
||||
test "preloads online status", %{account: account, unprivileged_subject: subject} do
|
||||
Fixtures.Clients.create_client(actor: subject.actor)
|
||||
|
||||
client_token =
|
||||
Fixtures.Tokens.create_client_token(
|
||||
account: account,
|
||||
actor: subject.actor,
|
||||
identity: subject.identity
|
||||
)
|
||||
|
||||
assert {:ok, [client], _metadata} = list_clients(subject, preload: [:online?])
|
||||
assert client.online? == false
|
||||
|
||||
{:ok, _} = Clients.Presence.Account.track(client.account_id, client.id)
|
||||
{:ok, _} = Clients.Presence.Actor.track(client.actor_id, client.id)
|
||||
{:ok, _} = Clients.Presence.Actor.track(client.actor_id, client.id, client_token.id)
|
||||
|
||||
assert {:ok, [client], _metadata} = list_clients(subject, preload: [:online?])
|
||||
assert client.online? == true
|
||||
@@ -957,7 +978,8 @@ defmodule Domain.ClientsTest do
|
||||
client = Fixtures.Clients.create_client()
|
||||
attrs = %{name: "new name"}
|
||||
|
||||
assert update_client(client, attrs, subject) == {:error, :not_found}
|
||||
assert update_client(client, attrs, subject) ==
|
||||
{:error, {:unauthorized, [reason: :incorrect_account]}}
|
||||
end
|
||||
|
||||
test "does not allow to reset required fields to empty values", %{
|
||||
@@ -1006,22 +1028,22 @@ defmodule Domain.ClientsTest do
|
||||
admin_subject: subject
|
||||
} do
|
||||
client = Fixtures.Clients.create_client(actor: actor)
|
||||
|
||||
subject = Fixtures.Auth.remove_permissions(subject)
|
||||
|
||||
assert update_client(client, %{}, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Clients.Authorizer.manage_own_clients_permission()]}}
|
||||
[
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [
|
||||
%Domain.Auth.Permission{resource: Domain.Clients.Client, action: :manage_own}
|
||||
]
|
||||
]}}
|
||||
|
||||
client = Fixtures.Clients.create_client()
|
||||
|
||||
assert update_client(client, %{}, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Clients.Authorizer.manage_clients_permission()]}}
|
||||
{:error, {:unauthorized, [reason: :incorrect_account]}}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1098,19 +1120,11 @@ defmodule Domain.ClientsTest do
|
||||
end
|
||||
|
||||
describe "delete_client/2" do
|
||||
test "returns error on state conflict", %{admin_actor: actor, admin_subject: subject} do
|
||||
client = Fixtures.Clients.create_client(actor: actor)
|
||||
|
||||
assert {:ok, deleted} = delete_client(client, subject)
|
||||
assert delete_client(deleted, subject) == {:error, :not_found}
|
||||
assert delete_client(client, subject) == {:error, :not_found}
|
||||
end
|
||||
|
||||
test "admin can delete own clients", %{admin_actor: actor, admin_subject: subject} do
|
||||
client = Fixtures.Clients.create_client(actor: actor)
|
||||
|
||||
assert {:ok, deleted} = delete_client(client, subject)
|
||||
assert deleted.deleted_at
|
||||
assert {:ok, _client} = delete_client(client, subject)
|
||||
refute Repo.get(Clients.Client, client.id)
|
||||
end
|
||||
|
||||
test "admin can delete other people clients", %{
|
||||
@@ -1119,8 +1133,8 @@ defmodule Domain.ClientsTest do
|
||||
} do
|
||||
client = Fixtures.Clients.create_client(actor: actor)
|
||||
|
||||
assert {:ok, deleted} = delete_client(client, subject)
|
||||
assert deleted.deleted_at
|
||||
assert {:ok, _client} = delete_client(client, subject)
|
||||
refute Repo.get(Clients.Client, client.id)
|
||||
end
|
||||
|
||||
test "admin cannot delete clients in other accounts", %{
|
||||
@@ -1128,39 +1142,43 @@ defmodule Domain.ClientsTest do
|
||||
} do
|
||||
client = Fixtures.Clients.create_client()
|
||||
|
||||
assert delete_client(client, subject) == {:error, :not_found}
|
||||
assert delete_client(client, subject) ==
|
||||
{:error, {:unauthorized, [reason: :incorrect_account]}}
|
||||
|
||||
assert c = Repo.get(Clients.Client, client.id)
|
||||
assert c.id == client.id
|
||||
end
|
||||
|
||||
test "unprivileged can delete own clients", %{
|
||||
test "unprivileged actor can delete own clients", %{
|
||||
account: account,
|
||||
unprivileged_actor: actor,
|
||||
unprivileged_subject: subject
|
||||
} do
|
||||
client = Fixtures.Clients.create_client(account: account, actor: actor)
|
||||
|
||||
assert {:ok, deleted} = delete_client(client, subject)
|
||||
assert deleted.deleted_at
|
||||
assert {:ok, _client} = delete_client(client, subject)
|
||||
refute Repo.get(Clients.Client, client.id)
|
||||
end
|
||||
|
||||
test "unprivileged cannot delete other people clients", %{
|
||||
test "unprivileged actor cannot delete other actor clients", %{
|
||||
account: account,
|
||||
unprivileged_subject: subject
|
||||
} do
|
||||
client = Fixtures.Clients.create_client()
|
||||
|
||||
assert delete_client(client, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Clients.Authorizer.manage_clients_permission()]}}
|
||||
{:error, {:unauthorized, [reason: :incorrect_account]}}
|
||||
|
||||
client = Fixtures.Clients.create_client(account: account)
|
||||
|
||||
assert delete_client(client, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Clients.Authorizer.manage_clients_permission()]}}
|
||||
[
|
||||
{:reason, :missing_permissions},
|
||||
{:missing_permissions,
|
||||
[%Domain.Auth.Permission{resource: Domain.Clients.Client, action: :manage}]}
|
||||
]}}
|
||||
|
||||
assert Repo.aggregate(Clients.Client, :count) == 2
|
||||
end
|
||||
@@ -1176,16 +1194,34 @@ defmodule Domain.ClientsTest do
|
||||
assert delete_client(client, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Clients.Authorizer.manage_own_clients_permission()]}}
|
||||
[
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [
|
||||
%Domain.Auth.Permission{resource: Domain.Clients.Client, action: :manage_own}
|
||||
]
|
||||
]}}
|
||||
|
||||
client = Fixtures.Clients.create_client()
|
||||
|
||||
assert delete_client(client, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Clients.Authorizer.manage_clients_permission()]}}
|
||||
{:error, {:unauthorized, [reason: :incorrect_account]}}
|
||||
end
|
||||
|
||||
test "raises error when deleting stale client structs", %{
|
||||
admin_actor: actor,
|
||||
admin_subject: subject
|
||||
} do
|
||||
client = Fixtures.Clients.create_client(actor: actor)
|
||||
|
||||
assert {:ok, deleted} = delete_client(client, subject)
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_client(deleted, subject)
|
||||
end
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_client(client, subject)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -51,16 +51,15 @@ defmodule Domain.GatewaysTest do
|
||||
assert fetch_group_by_id(group.id, subject) == {:error, :not_found}
|
||||
end
|
||||
|
||||
test "returns deleted groups", %{
|
||||
test "does not return deleted groups", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
group =
|
||||
{:ok, deleted_group} =
|
||||
Fixtures.Gateways.create_group(account: account)
|
||||
|> Fixtures.Gateways.delete_group()
|
||||
|
||||
assert {:ok, fetched_group} = fetch_group_by_id(group.id, subject)
|
||||
assert fetched_group.id == group.id
|
||||
assert {:error, :not_found} = fetch_group_by_id(deleted_group.id, subject)
|
||||
end
|
||||
|
||||
test "returns group by id", %{account: account, subject: subject} do
|
||||
@@ -344,19 +343,25 @@ defmodule Domain.GatewaysTest do
|
||||
end
|
||||
|
||||
describe "delete_group/2" do
|
||||
test "returns error on state conflict", %{account: account, subject: subject} do
|
||||
test "raises error when deleting stale group structs", %{account: account, subject: subject} do
|
||||
group = Fixtures.Gateways.create_group(account: account)
|
||||
|
||||
assert {:ok, deleted} = delete_group(group, subject)
|
||||
assert delete_group(deleted, subject) == {:error, :not_found}
|
||||
assert delete_group(group, subject) == {:error, :not_found}
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_group(deleted, subject)
|
||||
end
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_group(group, subject)
|
||||
end
|
||||
end
|
||||
|
||||
test "deletes groups", %{account: account, subject: subject} do
|
||||
test "deletes group", %{account: account, subject: subject} do
|
||||
group = Fixtures.Gateways.create_group(account: account)
|
||||
|
||||
assert {:ok, deleted} = delete_group(group, subject)
|
||||
assert deleted.deleted_at
|
||||
assert {:ok, _deleted_group} = delete_group(group, subject)
|
||||
refute Repo.get(Gateways.Group, group.id)
|
||||
end
|
||||
|
||||
test "deletes all tokens when group is deleted", %{account: account, subject: subject} do
|
||||
@@ -365,16 +370,14 @@ defmodule Domain.GatewaysTest do
|
||||
Fixtures.Gateways.create_token(account: account, group: [account: account])
|
||||
|
||||
assert {:ok, deleted} = delete_group(group, subject)
|
||||
assert deleted.deleted_at
|
||||
refute Repo.reload(deleted)
|
||||
|
||||
tokens =
|
||||
Domain.Tokens.Token.Query.all()
|
||||
|> Domain.Tokens.Token.Query.by_gateway_group_id(group.id)
|
||||
|> Repo.all()
|
||||
|> Enum.filter(fn token -> token.gateway_group_id == group.id end)
|
||||
|
||||
assert length(tokens) > 0
|
||||
assert Enum.all?(tokens, & &1.deleted_at)
|
||||
assert length(tokens) == 0
|
||||
end
|
||||
|
||||
test "deletes all gateways when group is deleted", %{account: account, subject: subject} do
|
||||
@@ -388,8 +391,7 @@ defmodule Domain.GatewaysTest do
|
||||
|> Domain.Gateways.Gateway.Query.by_group_id(group.id)
|
||||
|> Repo.all()
|
||||
|
||||
assert length(gateways) > 0
|
||||
assert Enum.all?(gateways, & &1.deleted_at)
|
||||
assert length(gateways) == 0
|
||||
end
|
||||
|
||||
test "deletes all connections when group is deleted", %{account: account, subject: subject} do
|
||||
@@ -421,11 +423,8 @@ defmodule Domain.GatewaysTest do
|
||||
|
||||
assert {:ok, _group} = delete_group(group, subject)
|
||||
|
||||
token1 = Repo.reload(token1)
|
||||
token2 = Repo.reload(token2)
|
||||
|
||||
assert token1.deleted_at
|
||||
assert token2.deleted_at
|
||||
refute Repo.reload(token1)
|
||||
refute Repo.reload(token2)
|
||||
end
|
||||
|
||||
test "returns error when subject has no permission to delete groups", %{
|
||||
@@ -435,11 +434,7 @@ defmodule Domain.GatewaysTest do
|
||||
|
||||
subject = Fixtures.Auth.remove_permissions(subject)
|
||||
|
||||
assert delete_group(group, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Gateways.Authorizer.manage_gateways_permission()]}}
|
||||
assert delete_group(group, subject) == {:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -573,15 +568,16 @@ defmodule Domain.GatewaysTest do
|
||||
assert fetch_gateway_by_id(gateway.id, subject) == {:error, :not_found}
|
||||
end
|
||||
|
||||
test "returns deleted gateways", %{
|
||||
test "does not return deleted gateways", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
gateway =
|
||||
deleted_gateway =
|
||||
Fixtures.Gateways.create_gateway(account: account)
|
||||
|> Fixtures.Gateways.delete_gateway()
|
||||
|
||||
assert fetch_gateway_by_id(gateway.id, subject, preload: :online?) == {:ok, gateway}
|
||||
assert fetch_gateway_by_id(deleted_gateway.id, subject, preload: :online?) ==
|
||||
{:error, :not_found}
|
||||
end
|
||||
|
||||
test "returns gateway by id", %{account: account, subject: subject} do
|
||||
@@ -650,7 +646,12 @@ defmodule Domain.GatewaysTest do
|
||||
} do
|
||||
offline_gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
online_gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
:ok = Gateways.Presence.connect(online_gateway)
|
||||
online_gateway = Repo.preload(online_gateway, :group)
|
||||
|
||||
gateway_token =
|
||||
Fixtures.Gateways.create_token(account: account, group: online_gateway.group)
|
||||
|
||||
:ok = Gateways.Presence.connect(online_gateway, gateway_token.id)
|
||||
Fixtures.Gateways.create_gateway()
|
||||
|
||||
assert {:ok, gateways, _metadata} = list_gateways(subject, preload: :online?)
|
||||
@@ -727,7 +728,9 @@ defmodule Domain.GatewaysTest do
|
||||
)
|
||||
|> to_cache()
|
||||
|
||||
assert Gateways.Presence.connect(gateway) == :ok
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
assert Gateways.Presence.connect(gateway, gateway_token.id) == :ok
|
||||
|
||||
assert {:ok, [connected_gateway]} =
|
||||
all_compatible_gateways_for_client_and_resource(client, resource, subject)
|
||||
@@ -750,7 +753,9 @@ defmodule Domain.GatewaysTest do
|
||||
)
|
||||
|> to_cache()
|
||||
|
||||
assert Gateways.Presence.connect(gateway) == :ok
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
assert Gateways.Presence.connect(gateway, gateway_token.id) == :ok
|
||||
|
||||
assert all_compatible_gateways_for_client_and_resource(client, resource, subject) ==
|
||||
{:ok, []}
|
||||
@@ -782,7 +787,9 @@ defmodule Domain.GatewaysTest do
|
||||
)
|
||||
|> to_cache()
|
||||
|
||||
assert Gateways.Presence.connect(gateway) == :ok
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
assert Gateways.Presence.connect(gateway, gateway_token.id) == :ok
|
||||
|
||||
assert all_compatible_gateways_for_client_and_resource(client, resource, subject) ==
|
||||
{:ok, []}
|
||||
@@ -796,7 +803,9 @@ defmodule Domain.GatewaysTest do
|
||||
resource = Fixtures.Resources.create_resource(account: account) |> to_cache()
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
|
||||
assert Gateways.Presence.connect(gateway) == :ok
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
assert Gateways.Presence.connect(gateway, gateway_token.id) == :ok
|
||||
|
||||
assert all_compatible_gateways_for_client_and_resource(client, resource, subject) ==
|
||||
{:ok, []}
|
||||
@@ -840,15 +849,14 @@ defmodule Domain.GatewaysTest do
|
||||
|
||||
test "returns errors on invalid attrs", %{
|
||||
context: context,
|
||||
group: group,
|
||||
token: token
|
||||
group: group
|
||||
} do
|
||||
attrs = %{
|
||||
external_id: nil,
|
||||
public_key: "x"
|
||||
}
|
||||
|
||||
assert {:error, changeset} = upsert_gateway(group, token, attrs, context)
|
||||
assert {:error, changeset} = upsert_gateway(group, attrs, context)
|
||||
|
||||
assert errors_on(changeset) == %{
|
||||
public_key: ["should be 44 character(s)", "must be a base64-encoded string"],
|
||||
@@ -858,14 +866,13 @@ defmodule Domain.GatewaysTest do
|
||||
|
||||
test "allows creating gateway with just required attributes", %{
|
||||
context: context,
|
||||
group: group,
|
||||
token: token
|
||||
group: group
|
||||
} do
|
||||
attrs =
|
||||
Fixtures.Gateways.gateway_attrs()
|
||||
|> Map.delete(:name)
|
||||
|
||||
assert {:ok, gateway} = upsert_gateway(group, token, attrs, context)
|
||||
assert {:ok, gateway} = upsert_gateway(group, attrs, context)
|
||||
|
||||
assert gateway.name
|
||||
assert gateway.public_key == attrs.public_key
|
||||
@@ -888,8 +895,7 @@ defmodule Domain.GatewaysTest do
|
||||
test "updates gateway when it already exists", %{
|
||||
account: account,
|
||||
context: context,
|
||||
group: group,
|
||||
token: token
|
||||
group: group
|
||||
} do
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account, group: group)
|
||||
attrs = Fixtures.Gateways.gateway_attrs(external_id: gateway.external_id)
|
||||
@@ -900,7 +906,7 @@ defmodule Domain.GatewaysTest do
|
||||
user_agent: "iOS/12.5 (iPhone) connlib/0.7.413"
|
||||
}
|
||||
|
||||
assert {:ok, updated_gateway} = upsert_gateway(group, token, attrs, context)
|
||||
assert {:ok, updated_gateway} = upsert_gateway(group, attrs, context)
|
||||
|
||||
assert Repo.aggregate(Gateways.Gateway, :count, :id) == 1
|
||||
|
||||
@@ -936,8 +942,7 @@ defmodule Domain.GatewaysTest do
|
||||
test "does not reserve additional addresses on update", %{
|
||||
account: account,
|
||||
context: context,
|
||||
group: group,
|
||||
token: token
|
||||
group: group
|
||||
} do
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account, group: group)
|
||||
|
||||
@@ -948,7 +953,7 @@ defmodule Domain.GatewaysTest do
|
||||
last_seen_remote_ip: %Postgrex.INET{address: {100, 64, 100, 100}}
|
||||
)
|
||||
|
||||
assert {:ok, updated_gateway} = upsert_gateway(group, token, attrs, context)
|
||||
assert {:ok, updated_gateway} = upsert_gateway(group, attrs, context)
|
||||
|
||||
addresses =
|
||||
Domain.Network.Address
|
||||
@@ -965,11 +970,10 @@ defmodule Domain.GatewaysTest do
|
||||
test "does not allow to reuse IP addresses", %{
|
||||
account: account,
|
||||
context: context,
|
||||
group: group,
|
||||
token: token
|
||||
group: group
|
||||
} do
|
||||
attrs = Fixtures.Gateways.gateway_attrs()
|
||||
assert {:ok, gateway} = upsert_gateway(group, token, attrs, context)
|
||||
assert {:ok, gateway} = upsert_gateway(group, attrs, context)
|
||||
|
||||
addresses =
|
||||
Domain.Network.Address
|
||||
@@ -1055,19 +1059,25 @@ defmodule Domain.GatewaysTest do
|
||||
end
|
||||
|
||||
describe "delete_gateway/2" do
|
||||
test "returns error on state conflict", %{account: account, subject: subject} do
|
||||
test "raises error when deleting stale gateway structs", %{account: account, subject: subject} do
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
|
||||
assert {:ok, deleted} = delete_gateway(gateway, subject)
|
||||
assert delete_gateway(deleted, subject) == {:error, :not_found}
|
||||
assert delete_gateway(gateway, subject) == {:error, :not_found}
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_gateway(deleted, subject)
|
||||
end
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_gateway(gateway, subject)
|
||||
end
|
||||
end
|
||||
|
||||
test "deletes gateways", %{account: account, subject: subject} do
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
|
||||
assert {:ok, deleted} = delete_gateway(gateway, subject)
|
||||
assert deleted.deleted_at
|
||||
refute Repo.reload(deleted)
|
||||
end
|
||||
|
||||
test "returns error when subject has no permission to delete gateways", %{
|
||||
@@ -1077,11 +1087,7 @@ defmodule Domain.GatewaysTest do
|
||||
|
||||
subject = Fixtures.Auth.remove_permissions(subject)
|
||||
|
||||
assert delete_gateway(gateway, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Gateways.Authorizer.manage_gateways_permission()]}}
|
||||
assert delete_gateway(gateway, subject) == {:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1270,15 +1276,19 @@ defmodule Domain.GatewaysTest do
|
||||
test "does not allow duplicate presence", %{account: account} do
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
|
||||
assert Gateways.Presence.connect(gateway) == :ok
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
assert Gateways.Presence.connect(gateway, gateway_token.id) == :ok
|
||||
|
||||
assert {:error, {:already_tracked, _pid, _topic, _key}} =
|
||||
Gateways.Presence.connect(gateway)
|
||||
Gateways.Presence.connect(gateway, gateway_token.id)
|
||||
end
|
||||
|
||||
test "tracks gateway presence for account", %{account: account} do
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account)
|
||||
assert Gateways.Presence.connect(gateway) == :ok
|
||||
gateway = Repo.preload(gateway, :group)
|
||||
gateway_token = Fixtures.Gateways.create_token(account: account, group: gateway.group)
|
||||
assert Gateways.Presence.connect(gateway, gateway_token.id) == :ok
|
||||
|
||||
gateway = fetch_gateway_by_id!(gateway.id, preload: [:online?])
|
||||
assert gateway.online? == true
|
||||
|
||||
@@ -21,16 +21,19 @@ defmodule Domain.Notifications.Jobs.OutdatedGatewaysTest do
|
||||
|> Fixtures.Accounts.change_to_enterprise()
|
||||
|
||||
gateway_group = Fixtures.Gateways.create_group(account: account)
|
||||
token = Fixtures.Gateways.create_token(account: account, group: gateway_group)
|
||||
|
||||
%{
|
||||
account: account,
|
||||
gateway_group: gateway_group
|
||||
gateway_group: gateway_group,
|
||||
token: token
|
||||
}
|
||||
end
|
||||
|
||||
test "sends notification for outdated gateways", %{
|
||||
account: account,
|
||||
gateway_group: gateway_group
|
||||
gateway_group: gateway_group,
|
||||
token: token
|
||||
} do
|
||||
# Create Gateway
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account, group: gateway_group)
|
||||
@@ -42,7 +45,7 @@ defmodule Domain.Notifications.Jobs.OutdatedGatewaysTest do
|
||||
Domain.Config.put_env_override(ComponentVersions, new_config)
|
||||
|
||||
:ok = Gateways.Presence.Group.subscribe(gateway_group.id)
|
||||
{:ok, _} = Gateways.Presence.Group.track(gateway.group_id, gateway.id)
|
||||
{:ok, _} = Gateways.Presence.Group.track(gateway.group_id, gateway.id, token.id)
|
||||
{:ok, _} = Gateways.Presence.Account.track(gateway.account_id, gateway.id)
|
||||
assert_receive %Phoenix.Socket.Broadcast{topic: "presences:group_gateways:" <> _}
|
||||
|
||||
@@ -56,7 +59,8 @@ defmodule Domain.Notifications.Jobs.OutdatedGatewaysTest do
|
||||
|
||||
test "does not send notification if gateway up to date", %{
|
||||
account: account,
|
||||
gateway_group: gateway_group
|
||||
gateway_group: gateway_group,
|
||||
token: token
|
||||
} do
|
||||
# Create Gateway
|
||||
gateway = Fixtures.Gateways.create_gateway(account: account, group: gateway_group)
|
||||
@@ -67,7 +71,7 @@ defmodule Domain.Notifications.Jobs.OutdatedGatewaysTest do
|
||||
Domain.Config.put_env_override(ComponentVersions, new_config)
|
||||
|
||||
:ok = Gateways.Presence.Group.subscribe(gateway_group.id)
|
||||
{:ok, _} = Gateways.Presence.Group.track(gateway.group_id, gateway.id)
|
||||
{:ok, _} = Gateways.Presence.Group.track(gateway.group_id, gateway.id, token.id)
|
||||
{:ok, _} = Gateways.Presence.Account.track(gateway.account_id, gateway.id)
|
||||
|
||||
assert_receive %Phoenix.Socket.Broadcast{topic: "presences:group_gateways:" <> _}
|
||||
|
||||
@@ -43,13 +43,11 @@ defmodule Domain.PoliciesTest do
|
||||
assert fetched_policy.id == policy.id
|
||||
end
|
||||
|
||||
test "returns deleted policies", %{account: account, subject: subject} do
|
||||
{:ok, policy} =
|
||||
Fixtures.Policies.create_policy(account: account)
|
||||
|> delete_policy(subject)
|
||||
test "does not return deleted policies", %{account: account, subject: subject} do
|
||||
policy = Fixtures.Policies.create_policy(account: account)
|
||||
delete_policy(policy, subject)
|
||||
|
||||
assert {:ok, fetched_policy} = fetch_policy_by_id(policy.id, subject)
|
||||
assert fetched_policy.id == policy.id
|
||||
assert {:error, :not_found} = fetch_policy_by_id(policy.id, subject)
|
||||
end
|
||||
|
||||
test "does not return policies in other accounts", %{subject: subject} do
|
||||
@@ -105,18 +103,11 @@ defmodule Domain.PoliciesTest do
|
||||
assert fetched_policy.id == policy.id
|
||||
end
|
||||
|
||||
test "returns deleted policies", %{account: account, subject: subject} do
|
||||
{:ok, policy} =
|
||||
Fixtures.Policies.create_policy(account: account)
|
||||
|> delete_policy(subject)
|
||||
test "does not return deleted policies", %{account: account, subject: subject} do
|
||||
policy = Fixtures.Policies.create_policy(account: account)
|
||||
delete_policy(policy, subject)
|
||||
|
||||
assert {:ok, fetched_policy} = fetch_policy_by_id_or_persistent_id(policy.id, subject)
|
||||
assert fetched_policy.id == policy.id
|
||||
|
||||
assert {:ok, fetched_policy} =
|
||||
fetch_policy_by_id_or_persistent_id(policy.persistent_id, subject)
|
||||
|
||||
assert fetched_policy.id == policy.id
|
||||
assert {:error, :not_found} = fetch_policy_by_id_or_persistent_id(policy.id, subject)
|
||||
end
|
||||
|
||||
test "does not return policies in other accounts", %{subject: subject} do
|
||||
@@ -725,8 +716,8 @@ defmodule Domain.PoliciesTest do
|
||||
end
|
||||
|
||||
test "deletes policy", %{policy: policy, subject: subject} do
|
||||
assert {:ok, deleted_policy} = delete_policy(policy, subject)
|
||||
assert deleted_policy.deleted_at != nil
|
||||
assert {:ok, _deleted_policy} = delete_policy(policy, subject)
|
||||
refute Repo.get(Policies.Policy, policy.id)
|
||||
end
|
||||
|
||||
test "returns error when subject has no permission to delete policies", %{
|
||||
@@ -738,21 +729,28 @@ defmodule Domain.PoliciesTest do
|
||||
assert delete_policy(policy, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Policies.Authorizer.manage_policies_permission()]}}
|
||||
[
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [
|
||||
%Domain.Auth.Permission{resource: Domain.Policies.Policy, action: :manage}
|
||||
]
|
||||
]}}
|
||||
end
|
||||
|
||||
test "returns error on state conflict", %{policy: policy, subject: subject} do
|
||||
assert {:ok, deleted_policy} = delete_policy(policy, subject)
|
||||
assert delete_policy(deleted_policy, subject) == {:error, :not_found}
|
||||
assert delete_policy(policy, subject) == {:error, :not_found}
|
||||
test "raises error when deleting stale policy structs", %{policy: policy, subject: subject} do
|
||||
assert {:ok, _deleted_policy} = delete_policy(policy, subject)
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_policy(policy, subject)
|
||||
end
|
||||
end
|
||||
|
||||
test "returns error when subject attempts to delete policy outside of account", %{
|
||||
policy: policy
|
||||
} do
|
||||
other_subject = Fixtures.Auth.create_subject()
|
||||
assert delete_policy(policy, other_subject) == {:error, :not_found}
|
||||
|
||||
assert delete_policy(policy, other_subject) == {:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -777,11 +775,8 @@ defmodule Domain.PoliciesTest do
|
||||
actor_group: actor_group,
|
||||
policy: policy
|
||||
} do
|
||||
assert {:ok, [deleted_policy]} = delete_policies_for(actor_group)
|
||||
refute is_nil(deleted_policy.deleted_at)
|
||||
assert deleted_policy.id == policy.id
|
||||
|
||||
refute is_nil(Repo.get(Policies.Policy, policy.id).deleted_at)
|
||||
assert {:ok, _count} = delete_policies_for(actor_group)
|
||||
refute Repo.get(Policies.Policy, policy.id)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -813,11 +808,9 @@ defmodule Domain.PoliciesTest do
|
||||
} do
|
||||
other_policy = Fixtures.Policies.create_policy(account: account, subject: subject)
|
||||
|
||||
assert {:ok, [deleted_policy]} = delete_policies_for(actor_group, subject)
|
||||
refute is_nil(deleted_policy.deleted_at)
|
||||
assert deleted_policy.id == policy.id
|
||||
assert {:ok, 1} = delete_policies_for(actor_group, subject)
|
||||
refute Repo.get(Policies.Policy, policy.id)
|
||||
|
||||
refute is_nil(Repo.get(Policies.Policy, policy.id).deleted_at)
|
||||
assert is_nil(Repo.get(Policies.Policy, other_policy.id).deleted_at)
|
||||
end
|
||||
|
||||
@@ -839,11 +832,9 @@ defmodule Domain.PoliciesTest do
|
||||
subject: subject
|
||||
)
|
||||
|
||||
assert {:ok, [deleted_policy]} = delete_policies_for(provider, subject)
|
||||
refute is_nil(deleted_policy.deleted_at)
|
||||
assert deleted_policy.id == policy.id
|
||||
assert {:ok, 1} = delete_policies_for(provider, subject)
|
||||
refute Repo.get(Policies.Policy, policy.id)
|
||||
|
||||
refute is_nil(Repo.get(Policies.Policy, policy.id).deleted_at)
|
||||
assert is_nil(Repo.get(Policies.Policy, other_policy.id).deleted_at)
|
||||
end
|
||||
|
||||
@@ -855,9 +846,8 @@ defmodule Domain.PoliciesTest do
|
||||
} do
|
||||
other_policy = Fixtures.Policies.create_policy(account: account, subject: subject)
|
||||
|
||||
assert {:ok, [deleted_policy]} = delete_policies_for(resource, subject)
|
||||
refute is_nil(deleted_policy.deleted_at)
|
||||
assert deleted_policy.id == policy.id
|
||||
assert {:ok, _deleted_policy} = delete_policies_for(resource, subject)
|
||||
refute Repo.get(Policies.Policy, policy.id)
|
||||
|
||||
assert is_nil(Repo.get(Policies.Policy, other_policy.id).deleted_at)
|
||||
end
|
||||
@@ -871,8 +861,12 @@ defmodule Domain.PoliciesTest do
|
||||
assert delete_policies_for(resource, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Policies.Authorizer.manage_policies_permission()]}}
|
||||
[
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [
|
||||
%Domain.Auth.Permission{resource: Domain.Policies.Policy, action: :manage}
|
||||
]
|
||||
]}}
|
||||
end
|
||||
|
||||
test "does not do anything on state conflict", %{
|
||||
@@ -880,16 +874,16 @@ defmodule Domain.PoliciesTest do
|
||||
actor_group: actor_group,
|
||||
subject: subject
|
||||
} do
|
||||
assert {:ok, [_deleted_policy]} = delete_policies_for(resource, subject)
|
||||
assert delete_policies_for(actor_group, subject) == {:ok, []}
|
||||
assert delete_policies_for(resource, subject) == {:ok, []}
|
||||
assert {:ok, _count} = delete_policies_for(resource, subject)
|
||||
assert delete_policies_for(actor_group, subject) == {:ok, 0}
|
||||
assert delete_policies_for(resource, subject) == {:ok, 0}
|
||||
end
|
||||
|
||||
test "does not delete policies outside of account", %{
|
||||
resource: resource
|
||||
} do
|
||||
subject = Fixtures.Auth.create_subject()
|
||||
assert delete_policies_for(resource, subject) == {:ok, []}
|
||||
assert delete_policies_for(resource, subject) == {:ok, 0}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ defmodule Domain.RelaysTest do
|
||||
assert fetch_group_by_id(group.id, subject) == {:error, :not_found}
|
||||
end
|
||||
|
||||
test "returns deleted groups", %{
|
||||
test "does not return deleted groups", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
@@ -37,8 +37,7 @@ defmodule Domain.RelaysTest do
|
||||
Fixtures.Relays.create_group(account: account)
|
||||
|> Fixtures.Relays.delete_group()
|
||||
|
||||
assert {:ok, fetched_group} = fetch_group_by_id(group.id, subject)
|
||||
assert fetched_group.id == group.id
|
||||
assert {:error, :not_found} = fetch_group_by_id(group.id, subject)
|
||||
end
|
||||
|
||||
test "returns group by id", %{account: account, subject: subject} do
|
||||
@@ -335,19 +334,28 @@ defmodule Domain.RelaysTest do
|
||||
end
|
||||
|
||||
describe "delete_group/2" do
|
||||
test "returns error on state conflict", %{account: account, subject: subject} do
|
||||
test "raises error when deleting stale relay group structs", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
group = Fixtures.Relays.create_group(account: account)
|
||||
|
||||
assert {:ok, deleted} = delete_group(group, subject)
|
||||
assert delete_group(deleted, subject) == {:error, :not_found}
|
||||
assert delete_group(group, subject) == {:error, :not_found}
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_group(deleted, subject)
|
||||
end
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_group(group, subject)
|
||||
end
|
||||
end
|
||||
|
||||
test "deletes groups", %{account: account, subject: subject} do
|
||||
group = Fixtures.Relays.create_group(account: account)
|
||||
|
||||
assert {:ok, deleted} = delete_group(group, subject)
|
||||
assert deleted.deleted_at
|
||||
assert {:ok, _group} = delete_group(group, subject)
|
||||
refute Repo.get(Relays.Group, group.id)
|
||||
end
|
||||
|
||||
test "does not allow deleting global group", %{subject: subject} do
|
||||
@@ -355,23 +363,24 @@ defmodule Domain.RelaysTest do
|
||||
assert delete_group(group, subject) == {:error, :unauthorized}
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - This test should be moved to Tokens since it holds the FK
|
||||
test "deletes all tokens when group is deleted", %{account: account, subject: subject} do
|
||||
group = Fixtures.Relays.create_group(account: account)
|
||||
Fixtures.Relays.create_token(account: account, group: group)
|
||||
Fixtures.Relays.create_token(account: account, group: [account: account])
|
||||
|
||||
assert {:ok, deleted} = delete_group(group, subject)
|
||||
assert deleted.deleted_at
|
||||
assert {:ok, _group} = delete_group(group, subject)
|
||||
refute Repo.get(Relays.Group, group.id)
|
||||
|
||||
tokens =
|
||||
Domain.Tokens.Token.Query.all()
|
||||
|> Domain.Tokens.Token.Query.by_relay_group_id(group.id)
|
||||
|> Repo.all()
|
||||
|
||||
assert length(tokens) > 0
|
||||
assert Enum.all?(tokens, & &1.deleted_at)
|
||||
assert length(tokens) == 0
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - This test should be moved to Tokens since it holds the FK
|
||||
test "deletes all relays when group is deleted", %{account: account, subject: subject} do
|
||||
group = Fixtures.Relays.create_group(account: account)
|
||||
Fixtures.Relays.create_relay(account: account, group: group)
|
||||
@@ -383,10 +392,10 @@ defmodule Domain.RelaysTest do
|
||||
|> Domain.Relays.Relay.Query.by_group_id(group.id)
|
||||
|> Repo.all()
|
||||
|
||||
assert length(relays) > 0
|
||||
assert Enum.all?(relays, & &1.deleted_at)
|
||||
assert length(relays) == 0
|
||||
end
|
||||
|
||||
# TODO: HARD-DELETE - This test should be moved to Tokens since it holds the FK
|
||||
test "deletes associated tokens", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
@@ -401,11 +410,8 @@ defmodule Domain.RelaysTest do
|
||||
|
||||
assert {:ok, _group} = delete_group(group, subject)
|
||||
|
||||
token1 = Repo.reload(token1)
|
||||
token2 = Repo.reload(token2)
|
||||
|
||||
assert token1.deleted_at
|
||||
assert token2.deleted_at
|
||||
refute Repo.reload(token1)
|
||||
refute Repo.reload(token2)
|
||||
end
|
||||
|
||||
test "returns error when subject has no permission to delete groups", %{
|
||||
@@ -415,11 +421,7 @@ defmodule Domain.RelaysTest do
|
||||
|
||||
subject = Fixtures.Auth.remove_permissions(subject)
|
||||
|
||||
assert delete_group(group, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Relays.Authorizer.manage_relays_permission()]}}
|
||||
assert delete_group(group, subject) == {:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -633,7 +635,7 @@ defmodule Domain.RelaysTest do
|
||||
assert fetch_relay_by_id(relay.id, subject) == {:error, :not_found}
|
||||
end
|
||||
|
||||
test "returns deleted relays", %{
|
||||
test "does not return deleted relays", %{
|
||||
account: account,
|
||||
subject: subject
|
||||
} do
|
||||
@@ -641,7 +643,7 @@ defmodule Domain.RelaysTest do
|
||||
Fixtures.Relays.create_relay(account: account)
|
||||
|> Fixtures.Relays.delete_relay()
|
||||
|
||||
assert {:ok, _relay} = fetch_relay_by_id(relay.id, subject)
|
||||
assert {:error, :not_found} = fetch_relay_by_id(relay.id, subject)
|
||||
end
|
||||
|
||||
test "returns relay by id", %{account: account, subject: subject} do
|
||||
@@ -698,13 +700,15 @@ defmodule Domain.RelaysTest do
|
||||
Fixtures.Relays.create_relay()
|
||||
|
||||
group = Fixtures.Relays.create_global_group()
|
||||
relay = Fixtures.Relays.create_relay(account: account, group: group)
|
||||
relay = Fixtures.Relays.create_relay(account: account, group: group) |> Repo.preload(:group)
|
||||
|
||||
assert {:ok, relays, _metadata} = list_relays(subject, preload: :online?)
|
||||
assert length(relays) == 3
|
||||
refute Enum.any?(relays, & &1.online?)
|
||||
|
||||
:ok = connect_relay(relay, Ecto.UUID.generate())
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay.group)
|
||||
|
||||
:ok = connect_relay(relay, Ecto.UUID.generate(), relay_token.id)
|
||||
assert {:ok, relays, _metadata} = list_relays(subject, preload: :online?)
|
||||
assert length(relays) == 3
|
||||
assert Enum.any?(relays, & &1.online?)
|
||||
@@ -747,12 +751,17 @@ defmodule Domain.RelaysTest do
|
||||
# end
|
||||
|
||||
test "returns list of connected account relays", %{account: account} do
|
||||
relay1 = Fixtures.Relays.create_relay(account: account)
|
||||
relay2 = Fixtures.Relays.create_relay(account: account)
|
||||
relay1 = Fixtures.Relays.create_relay(account: account) |> Repo.preload(:group)
|
||||
relay2 = Fixtures.Relays.create_relay(account: account) |> Repo.preload(:group)
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
|
||||
assert connect_relay(relay1, stamp_secret) == :ok
|
||||
assert connect_relay(relay2, stamp_secret) == :ok
|
||||
relay1_token = Fixtures.Relays.create_token(group: relay1.group, account: account)
|
||||
|
||||
assert connect_relay(relay1, stamp_secret, relay1_token.id) == :ok
|
||||
|
||||
relay2_token = Fixtures.Relays.create_token(group: relay2.group, account: account)
|
||||
|
||||
assert connect_relay(relay2, stamp_secret, relay2_token.id) == :ok
|
||||
|
||||
Fixtures.Relays.update_relay(relay1,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-6, :second)
|
||||
@@ -770,10 +779,11 @@ defmodule Domain.RelaysTest do
|
||||
|
||||
test "returns list of connected global relays", %{account: account} do
|
||||
group = Fixtures.Relays.create_global_group()
|
||||
relay = Fixtures.Relays.create_relay(account: account, group: group)
|
||||
relay = Fixtures.Relays.create_relay(account: account, group: group) |> Repo.preload(:group)
|
||||
relay_token = Fixtures.Relays.create_global_token(group: relay.group)
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
|
||||
assert connect_relay(relay, stamp_secret) == :ok
|
||||
assert connect_relay(relay, stamp_secret, relay_token.id) == :ok
|
||||
|
||||
Fixtures.Relays.update_relay(relay,
|
||||
last_seen_at: DateTime.utc_now() |> DateTime.add(-10, :second)
|
||||
@@ -811,14 +821,12 @@ defmodule Domain.RelaysTest do
|
||||
describe "upsert_relay/3" do
|
||||
setup %{account: account} do
|
||||
group = Fixtures.Relays.create_group(account: account)
|
||||
token = Fixtures.Relays.create_token(account: account, group: group)
|
||||
|
||||
user_agent = Fixtures.Auth.user_agent()
|
||||
remote_ip = Fixtures.Auth.remote_ip()
|
||||
|
||||
%{
|
||||
group: group,
|
||||
token: token,
|
||||
context: %Domain.Auth.Context{
|
||||
type: :relay_group,
|
||||
remote_ip: remote_ip,
|
||||
@@ -833,8 +841,7 @@ defmodule Domain.RelaysTest do
|
||||
|
||||
test "returns errors on invalid attrs", %{
|
||||
context: context,
|
||||
group: group,
|
||||
token: token
|
||||
group: group
|
||||
} do
|
||||
attrs = %{
|
||||
ipv4: "1.1.1.256",
|
||||
@@ -842,7 +849,7 @@ defmodule Domain.RelaysTest do
|
||||
port: -1
|
||||
}
|
||||
|
||||
assert {:error, changeset} = upsert_relay(group, token, attrs, context)
|
||||
assert {:error, changeset} = upsert_relay(group, attrs, context)
|
||||
|
||||
assert errors_on(changeset) == %{
|
||||
ipv4: ["one of these fields must be present: ipv4, ipv6", "is invalid"],
|
||||
@@ -851,20 +858,19 @@ defmodule Domain.RelaysTest do
|
||||
}
|
||||
|
||||
attrs = %{port: 100_000}
|
||||
assert {:error, changeset} = upsert_relay(group, token, attrs, context)
|
||||
assert {:error, changeset} = upsert_relay(group, attrs, context)
|
||||
assert "must be less than or equal to 65535" in errors_on(changeset).port
|
||||
end
|
||||
|
||||
test "allows creating relay with just required attributes", %{
|
||||
context: context,
|
||||
group: group,
|
||||
token: token
|
||||
group: group
|
||||
} do
|
||||
attrs =
|
||||
Fixtures.Relays.relay_attrs()
|
||||
|> Map.delete(:name)
|
||||
|
||||
assert {:ok, relay} = upsert_relay(group, token, attrs, context)
|
||||
assert {:ok, relay} = upsert_relay(group, attrs, context)
|
||||
|
||||
assert relay.group_id == group.id
|
||||
|
||||
@@ -879,7 +885,6 @@ defmodule Domain.RelaysTest do
|
||||
assert relay.last_seen_user_agent == context.user_agent
|
||||
assert relay.last_seen_version == "1.3.0"
|
||||
assert relay.last_seen_at
|
||||
assert relay.last_used_token_id == token.id
|
||||
assert relay.port == 3478
|
||||
|
||||
assert Repo.aggregate(Domain.Network.Address, :count) == 0
|
||||
@@ -887,15 +892,14 @@ defmodule Domain.RelaysTest do
|
||||
|
||||
test "allows creating ipv6-only relays", %{
|
||||
context: context,
|
||||
group: group,
|
||||
token: token
|
||||
group: group
|
||||
} do
|
||||
attrs =
|
||||
Fixtures.Relays.relay_attrs()
|
||||
|> Map.drop([:name, :ipv4])
|
||||
|
||||
assert {:ok, _relay} = upsert_relay(group, token, attrs, context)
|
||||
assert {:ok, _relay} = upsert_relay(group, token, attrs, context)
|
||||
assert {:ok, _relay} = upsert_relay(group, attrs, context)
|
||||
assert {:ok, _relay} = upsert_relay(group, attrs, context)
|
||||
|
||||
assert Repo.one(Relays.Relay)
|
||||
end
|
||||
@@ -903,14 +907,13 @@ defmodule Domain.RelaysTest do
|
||||
test "updates ipv4 relay when it already exists", %{
|
||||
account: account,
|
||||
group: group,
|
||||
token: token,
|
||||
context: context
|
||||
} do
|
||||
relay = Fixtures.Relays.create_relay(account: account, group: group)
|
||||
attrs = Fixtures.Relays.relay_attrs(ipv4: relay.ipv4)
|
||||
context = %{context | user_agent: "iOS/12.5 (iPhone) connlib/0.7.411"}
|
||||
|
||||
assert {:ok, updated_relay} = upsert_relay(group, token, attrs, context)
|
||||
assert {:ok, updated_relay} = upsert_relay(group, attrs, context)
|
||||
|
||||
assert Repo.aggregate(Relays.Relay, :count, :id) == 1
|
||||
|
||||
@@ -920,7 +923,6 @@ defmodule Domain.RelaysTest do
|
||||
assert updated_relay.last_seen_version == "0.7.411"
|
||||
assert updated_relay.last_seen_at
|
||||
assert updated_relay.last_seen_at != relay.last_seen_at
|
||||
assert updated_relay.last_used_token_id == token.id
|
||||
|
||||
assert updated_relay.group_id == group.id
|
||||
|
||||
@@ -942,8 +944,7 @@ defmodule Domain.RelaysTest do
|
||||
test "updates ipv6 relay when it already exists", %{
|
||||
context: context,
|
||||
account: account,
|
||||
group: group,
|
||||
token: token
|
||||
group: group
|
||||
} do
|
||||
relay = Fixtures.Relays.create_relay(ipv4: nil, account: account, group: group)
|
||||
|
||||
@@ -953,7 +954,7 @@ defmodule Domain.RelaysTest do
|
||||
ipv6: relay.ipv6
|
||||
)
|
||||
|
||||
assert {:ok, updated_relay} = upsert_relay(group, token, attrs, context)
|
||||
assert {:ok, updated_relay} = upsert_relay(group, attrs, context)
|
||||
|
||||
assert Repo.aggregate(Relays.Relay, :count, :id) == 1
|
||||
|
||||
@@ -962,7 +963,6 @@ defmodule Domain.RelaysTest do
|
||||
assert updated_relay.last_seen_version == "1.3.0"
|
||||
assert updated_relay.last_seen_at
|
||||
assert updated_relay.last_seen_at != relay.last_seen_at
|
||||
assert updated_relay.last_used_token_id == token.id
|
||||
|
||||
assert updated_relay.group_id == group.id
|
||||
|
||||
@@ -975,12 +975,11 @@ defmodule Domain.RelaysTest do
|
||||
|
||||
test "updates global relay when it already exists", %{context: context} do
|
||||
group = Fixtures.Relays.create_global_group()
|
||||
token = Fixtures.Relays.create_global_token(group: group)
|
||||
relay = Fixtures.Relays.create_relay(group: group)
|
||||
context = %{context | user_agent: "iOS/12.5 (iPhone) connlib/0.7.411"}
|
||||
attrs = Fixtures.Relays.relay_attrs(ipv4: relay.ipv4)
|
||||
|
||||
assert {:ok, updated_relay} = upsert_relay(group, token, attrs, context)
|
||||
assert {:ok, updated_relay} = upsert_relay(group, attrs, context)
|
||||
|
||||
assert Repo.aggregate(Relays.Relay, :count, :id) == 1
|
||||
|
||||
@@ -990,7 +989,6 @@ defmodule Domain.RelaysTest do
|
||||
assert updated_relay.last_seen_version == "0.7.411"
|
||||
assert updated_relay.last_seen_at
|
||||
assert updated_relay.last_seen_at != relay.last_seen_at
|
||||
assert updated_relay.last_used_token_id == token.id
|
||||
|
||||
assert updated_relay.group_id == group.id
|
||||
|
||||
@@ -1039,19 +1037,25 @@ defmodule Domain.RelaysTest do
|
||||
end
|
||||
|
||||
describe "delete_relay/2" do
|
||||
test "returns error on state conflict", %{account: account, subject: subject} do
|
||||
test "raises error when deleting stale relay structs", %{account: account, subject: subject} do
|
||||
relay = Fixtures.Relays.create_relay(account: account)
|
||||
|
||||
assert {:ok, deleted} = delete_relay(relay, subject)
|
||||
assert delete_relay(deleted, subject) == {:error, :not_found}
|
||||
assert delete_relay(relay, subject) == {:error, :not_found}
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_relay(deleted, subject)
|
||||
end
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_relay(relay, subject)
|
||||
end
|
||||
end
|
||||
|
||||
test "deletes relays", %{account: account, subject: subject} do
|
||||
relay = Fixtures.Relays.create_relay(account: account)
|
||||
|
||||
assert {:ok, deleted} = delete_relay(relay, subject)
|
||||
assert deleted.deleted_at
|
||||
assert {:ok, _relay} = delete_relay(relay, subject)
|
||||
refute Repo.get(Relays.Relay, relay.id)
|
||||
end
|
||||
|
||||
test "returns error when subject has no permission to delete relays", %{
|
||||
@@ -1061,11 +1065,7 @@ defmodule Domain.RelaysTest do
|
||||
|
||||
subject = Fixtures.Auth.remove_permissions(subject)
|
||||
|
||||
assert delete_relay(relay, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Relays.Authorizer.manage_relays_permission()]}}
|
||||
assert delete_relay(relay, subject) == {:error, :unauthorized}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1312,26 +1312,33 @@ defmodule Domain.RelaysTest do
|
||||
end
|
||||
end
|
||||
|
||||
describe "connect_relay/2" do
|
||||
describe "connect_relay/3" do
|
||||
test "does not allow duplicate presence", %{account: account} do
|
||||
relay = Fixtures.Relays.create_relay(account: account)
|
||||
relay = Fixtures.Relays.create_relay(account: account) |> Repo.preload(:group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
stamp_secret = Ecto.UUID.generate()
|
||||
|
||||
assert connect_relay(relay, stamp_secret) == :ok
|
||||
assert {:error, {:already_tracked, _pid, _topic, _key}} = connect_relay(relay, stamp_secret)
|
||||
assert connect_relay(relay, stamp_secret, relay_token.id) == :ok
|
||||
|
||||
assert {:error, {:already_tracked, _pid, _topic, _key}} =
|
||||
connect_relay(relay, stamp_secret, relay_token.id)
|
||||
end
|
||||
|
||||
test "tracks relay presence for account", %{account: account} do
|
||||
relay = Fixtures.Relays.create_relay(account: account)
|
||||
assert connect_relay(relay, "foo") == :ok
|
||||
relay = Fixtures.Relays.create_relay(account: account) |> Repo.preload(:group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
|
||||
assert connect_relay(relay, "foo", relay_token.id) == :ok
|
||||
|
||||
relay = fetch_relay_by_id!(relay.id, preload: [:online?])
|
||||
assert relay.online? == true
|
||||
end
|
||||
|
||||
test "tracks relay presence for actor", %{account: account} do
|
||||
relay = Fixtures.Relays.create_relay(account: account)
|
||||
assert connect_relay(relay, "foo") == :ok
|
||||
relay = Fixtures.Relays.create_relay(account: account) |> Repo.preload(:group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
|
||||
assert connect_relay(relay, "foo", relay_token.id) == :ok
|
||||
|
||||
assert broadcast_to_relay(relay, "test") == :ok
|
||||
|
||||
@@ -1339,8 +1346,10 @@ defmodule Domain.RelaysTest do
|
||||
end
|
||||
|
||||
test "subscribes to relay events", %{account: account} do
|
||||
relay = Fixtures.Relays.create_relay(account: account)
|
||||
assert connect_relay(relay, "foo") == :ok
|
||||
relay = Fixtures.Relays.create_relay(account: account) |> Repo.preload(:group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
|
||||
assert connect_relay(relay, "foo", relay_token.id) == :ok
|
||||
|
||||
assert disconnect_relay(relay) == :ok
|
||||
|
||||
@@ -1349,9 +1358,10 @@ defmodule Domain.RelaysTest do
|
||||
|
||||
test "subscribes to relay group events", %{account: account} do
|
||||
group = Fixtures.Relays.create_group(account: account)
|
||||
relay = Fixtures.Relays.create_relay(account: account, group: group)
|
||||
relay = Fixtures.Relays.create_relay(account: account, group: group) |> Repo.preload(:group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
|
||||
assert connect_relay(relay, "foo") == :ok
|
||||
assert connect_relay(relay, "foo", relay_token.id) == :ok
|
||||
|
||||
assert disconnect_relays_in_group(group) == :ok
|
||||
|
||||
@@ -1359,9 +1369,10 @@ defmodule Domain.RelaysTest do
|
||||
end
|
||||
|
||||
test "subscribes to account events", %{account: account} do
|
||||
relay = Fixtures.Relays.create_relay(account: account)
|
||||
relay = Fixtures.Relays.create_relay(account: account) |> Repo.preload(:group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
|
||||
assert connect_relay(relay, "foo") == :ok
|
||||
assert connect_relay(relay, "foo", relay_token.id) == :ok
|
||||
|
||||
assert disconnect_relays_in_account(account) == :ok
|
||||
|
||||
@@ -1369,10 +1380,11 @@ defmodule Domain.RelaysTest do
|
||||
end
|
||||
|
||||
test "subscribes to relay presence", %{account: account} do
|
||||
relay = Fixtures.Relays.create_relay(account: account)
|
||||
relay = Fixtures.Relays.create_relay(account: account) |> Repo.preload(:group)
|
||||
relay_token = Fixtures.Relays.create_token(group: relay.group, account: account)
|
||||
:ok = subscribe_to_relay_presence(relay)
|
||||
|
||||
assert connect_relay(relay, "foo") == :ok
|
||||
assert connect_relay(relay, "foo", relay_token.id) == :ok
|
||||
|
||||
relay_id = relay.id
|
||||
assert_receive %Phoenix.Socket.Broadcast{topic: "presences:relays:" <> ^relay_id}
|
||||
|
||||
@@ -60,12 +60,11 @@ defmodule Domain.ResourcesTest do
|
||||
assert Enum.map(fetched_resource.authorized_by_policies, & &1.id) == [policy.id]
|
||||
end
|
||||
|
||||
test "returns deleted resources", %{account: account, subject: subject} do
|
||||
{:ok, resource} =
|
||||
Fixtures.Resources.create_resource(account: account)
|
||||
|> delete_resource(subject)
|
||||
test "does not return deleted resources", %{account: account, subject: subject} do
|
||||
resource = Fixtures.Resources.create_resource(account: account)
|
||||
delete_resource(resource, subject)
|
||||
|
||||
assert {:ok, _resource} = fetch_resource_by_id(resource.id, subject)
|
||||
assert {:error, :not_found} = fetch_resource_by_id(resource.id, subject)
|
||||
end
|
||||
|
||||
test "does not return resources in other accounts", %{subject: subject} do
|
||||
@@ -161,14 +160,13 @@ defmodule Domain.ResourcesTest do
|
||||
assert Enum.map(fetched_resource.authorized_by_policies, & &1.id) == [policy.id]
|
||||
end
|
||||
|
||||
test "returns deleted resources", %{account: account, subject: subject} do
|
||||
{:ok, resource} =
|
||||
Fixtures.Resources.create_resource(account: account)
|
||||
|> delete_resource(subject)
|
||||
test "does not return deleted resources", %{account: account, subject: subject} do
|
||||
resource = Fixtures.Resources.create_resource(account: account)
|
||||
delete_resource(resource, subject)
|
||||
|
||||
assert {:ok, _resource} = fetch_resource_by_id_or_persistent_id(resource.id, subject)
|
||||
assert {:error, :not_found} = fetch_resource_by_id_or_persistent_id(resource.id, subject)
|
||||
|
||||
assert {:ok, _resource} =
|
||||
assert {:error, :not_found} =
|
||||
fetch_resource_by_id_or_persistent_id(resource.persistent_id, subject)
|
||||
end
|
||||
|
||||
@@ -1399,18 +1397,20 @@ defmodule Domain.ResourcesTest do
|
||||
%{resource: resource}
|
||||
end
|
||||
|
||||
test "returns error on state conflict", %{
|
||||
test "raises error when deleting stale resource structs", %{
|
||||
resource: resource,
|
||||
subject: subject
|
||||
} do
|
||||
assert {:ok, deleted} = delete_resource(resource, subject)
|
||||
assert delete_resource(deleted, subject) == {:error, :not_found}
|
||||
assert delete_resource(resource, subject) == {:error, :not_found}
|
||||
assert {:ok, _resource} = delete_resource(resource, subject)
|
||||
|
||||
assert_raise Ecto.StaleEntryError, fn ->
|
||||
delete_resource(resource, subject)
|
||||
end
|
||||
end
|
||||
|
||||
test "deletes resources", %{resource: resource, subject: subject} do
|
||||
assert {:ok, deleted} = delete_resource(resource, subject)
|
||||
assert deleted.deleted_at
|
||||
assert {:ok, _resource} = delete_resource(resource, subject)
|
||||
refute Repo.get(Resources.Resource, resource.id)
|
||||
end
|
||||
|
||||
test "deletes policies that use this resource", %{
|
||||
@@ -1423,8 +1423,8 @@ defmodule Domain.ResourcesTest do
|
||||
|
||||
assert {:ok, _resource} = delete_resource(resource, subject)
|
||||
|
||||
refute is_nil(Repo.get_by(Domain.Policies.Policy, id: policy.id).deleted_at)
|
||||
assert is_nil(Repo.get_by(Domain.Policies.Policy, id: other_policy.id).deleted_at)
|
||||
assert is_nil(Repo.get(Domain.Policies.Policy, policy.id))
|
||||
assert Repo.get(Domain.Policies.Policy, other_policy.id) == other_policy
|
||||
end
|
||||
|
||||
test "deletes connections that use this resource", %{
|
||||
@@ -1453,8 +1453,12 @@ defmodule Domain.ResourcesTest do
|
||||
assert delete_resource(resource, subject) ==
|
||||
{:error,
|
||||
{:unauthorized,
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [Resources.Authorizer.manage_resources_permission()]}}
|
||||
[
|
||||
reason: :missing_permissions,
|
||||
missing_permissions: [
|
||||
%Domain.Auth.Permission{resource: Domain.Resources.Resource, action: :manage}
|
||||
]
|
||||
]}}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user