mirror of
https://github.com/outbackdingo/firezone.git
synced 2026-01-27 10:18:54 +00:00
fix(portal): Ship hotfixes for various crash reports discovered in logs (#4538)
I'll merge and push this right away to prevent users from hitting edge cases and our monitoring from triggering alerts.
This commit is contained in:
@@ -34,6 +34,10 @@ defmodule API.Client.Channel do
|
||||
|
||||
defp schedule_expiration(%{assigns: %{subject: %{expires_at: expires_at}}} = socket) do
|
||||
expires_in = DateTime.diff(expires_at, DateTime.utc_now(), :millisecond)
|
||||
# Protect from race conditions where the token might have expired during code execution
|
||||
expires_in = max(0, expires_in)
|
||||
# Expiration time is capped at 31 days even if IdP returns really long lived tokens
|
||||
expires_in = min(expires_in, 2_678_400_000)
|
||||
|
||||
if expires_in > 0 do
|
||||
Process.send_after(self(), :token_expired, expires_in)
|
||||
|
||||
@@ -113,6 +113,31 @@ defmodule API.Client.ChannelTest do
|
||||
assert is_number(online_at)
|
||||
end
|
||||
|
||||
test "does not crash when subject expiration is too large", %{
|
||||
client: client,
|
||||
subject: subject
|
||||
} do
|
||||
expires_at = DateTime.utc_now() |> DateTime.add(100_000_000_000, :millisecond)
|
||||
subject = %{subject | expires_at: expires_at}
|
||||
|
||||
# We need to trap exits to avoid test process termination
|
||||
# because it is linked to the created test channel process
|
||||
Process.flag(:trap_exit, true)
|
||||
|
||||
{:ok, _reply, _socket} =
|
||||
API.Client.Socket
|
||||
|> socket("client:#{client.id}", %{
|
||||
opentelemetry_ctx: OpenTelemetry.Ctx.new(),
|
||||
opentelemetry_span_ctx: OpenTelemetry.Tracer.start_span("test"),
|
||||
client: client,
|
||||
subject: subject
|
||||
})
|
||||
|> subscribe_and_join(API.Client.Channel, "client")
|
||||
|
||||
refute_receive {:EXIT, _pid, _}
|
||||
refute_receive {:socket_close, _pid, _}
|
||||
end
|
||||
|
||||
test "expires the channel when token is expired", %{client: client, subject: subject} do
|
||||
expires_at = DateTime.utc_now() |> DateTime.add(25, :millisecond)
|
||||
subject = %{subject | expires_at: expires_at}
|
||||
|
||||
@@ -97,7 +97,7 @@ defmodule Domain.Flows.Flow.Query do
|
||||
@impl Domain.Repo.Query
|
||||
def cursor_fields,
|
||||
do: [
|
||||
{:flows, :asc, :inserted_at},
|
||||
{:flows, :desc, :inserted_at},
|
||||
{:flows, :asc, :id}
|
||||
]
|
||||
end
|
||||
|
||||
@@ -32,7 +32,7 @@ defmodule Web.Flows.Show do
|
||||
|
||||
{:ok, socket}
|
||||
else
|
||||
{:error, _reason} -> raise Web.LiveErrors.NotFoundError
|
||||
_other -> raise Web.LiveErrors.NotFoundError
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ defmodule Web.Resources.Show do
|
||||
socket,
|
||||
page_title: "Resource #{resource.name}",
|
||||
traffic_filters_enabled?: Accounts.traffic_filters_enabled?(socket.assigns.account),
|
||||
flow_activities_enabled?: Accounts.flow_activities_enabled?(socket.assigns.account),
|
||||
resource: resource,
|
||||
actor_groups_peek: Map.fetch!(actor_groups_peek, resource.id),
|
||||
params: Map.take(params, ["site_id"])
|
||||
@@ -298,7 +299,7 @@ defmodule Web.Resources.Show do
|
||||
</.link>
|
||||
(<%= flow.gateway_remote_ip %>)
|
||||
</:col>
|
||||
<:col :let={flow} label="ACTIVITY">
|
||||
<:col :let={flow} :if={@flow_activities_enabled?} label="ACTIVITY">
|
||||
<.link navigate={~p"/#{@account}/flows/#{flow.id}"} class={[link_style()]}>
|
||||
Show
|
||||
</.link>
|
||||
|
||||
@@ -28,6 +28,10 @@ defmodule Web.SignIn.Email do
|
||||
{:ok, socket, temporary_assigns: [form: %Phoenix.HTML.Form{}]}
|
||||
end
|
||||
|
||||
def mount(_params, _session, _socket) do
|
||||
raise Web.LiveErrors.NotFoundError
|
||||
end
|
||||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<section>
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
defmodule Web.SignIn.Success do
|
||||
use Web, {:live_view, layout: {Web.Layouts, :public}}
|
||||
|
||||
def mount(params, _session, socket) do
|
||||
def mount(
|
||||
%{
|
||||
"fragment" => _,
|
||||
"state" => _,
|
||||
"actor_name" => _,
|
||||
"identity_provider_identifier" => _
|
||||
} = params,
|
||||
_session,
|
||||
socket
|
||||
) do
|
||||
if connected?(socket) do
|
||||
Process.send_after(self(), :redirect_client, 100)
|
||||
end
|
||||
@@ -16,6 +25,10 @@ defmodule Web.SignIn.Success do
|
||||
{:ok, socket}
|
||||
end
|
||||
|
||||
def mount(_params, _session, _socket) do
|
||||
raise Web.LiveErrors.InvalidParamsError
|
||||
end
|
||||
|
||||
def render(assigns) do
|
||||
~H"""
|
||||
<section>
|
||||
|
||||
@@ -22,7 +22,8 @@ defmodule Web.SignUp do
|
||||
%Registration{}
|
||||
|> Ecto.Changeset.cast(attrs, [:email])
|
||||
|> Ecto.Changeset.validate_required([:email])
|
||||
|> Ecto.Changeset.validate_format(:email, ~r/.+@.+/)
|
||||
|> Domain.Repo.Changeset.trim_change(:email)
|
||||
|> Domain.Repo.Changeset.validate_email(:email)
|
||||
|> validate_email_allowed(whitelisted_domains)
|
||||
|> Ecto.Changeset.validate_confirmation(:email,
|
||||
required: true,
|
||||
|
||||
@@ -7,4 +7,15 @@ defmodule Web.LiveErrors do
|
||||
def actions(_exception), do: []
|
||||
end
|
||||
end
|
||||
|
||||
# this is not a styled error because only security scanners that
|
||||
# try to manipulate the request will see it
|
||||
defmodule InvalidParamsError do
|
||||
defexception message: "Unprocessable Entity"
|
||||
|
||||
defimpl Plug.Exception do
|
||||
def status(_exception), do: 422
|
||||
def actions(_exception), do: []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -36,6 +36,26 @@ defmodule Web.Live.Flows.ShowTest do
|
||||
}}}
|
||||
end
|
||||
|
||||
test "renders 404 error when flow activities are not enabled", %{
|
||||
account: account,
|
||||
identity: identity,
|
||||
flow: flow,
|
||||
conn: conn
|
||||
} do
|
||||
{:ok, account} =
|
||||
Domain.Accounts.update_account(account, %{
|
||||
features: %{
|
||||
flow_activities: false
|
||||
}
|
||||
})
|
||||
|
||||
assert_raise Web.LiveErrors.NotFoundError, fn ->
|
||||
conn
|
||||
|> authorize_conn(identity)
|
||||
|> live(~p"/#{account}/flows/#{flow}") =~ "404"
|
||||
end
|
||||
end
|
||||
|
||||
test "renders breadcrumbs item", %{
|
||||
account: account,
|
||||
flow: flow,
|
||||
|
||||
@@ -34,4 +34,13 @@ defmodule Web.SignIn.SuccessTest do
|
||||
uri = URI.parse(path)
|
||||
assert URI.decode_query(uri.query) == expected_query_params
|
||||
end
|
||||
|
||||
test "returns 422 error when params are missing", %{
|
||||
account: account,
|
||||
conn: conn
|
||||
} do
|
||||
assert_raise Web.LiveErrors.InvalidParamsError, fn ->
|
||||
live(conn, ~p"/#{account}/sign_in/success")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -75,6 +75,42 @@ defmodule Web.Live.SignUpTest do
|
||||
end)
|
||||
end
|
||||
|
||||
test "trims the user email", %{conn: conn} do
|
||||
Domain.Config.put_env_override(:outbound_email_adapter_configured?, true)
|
||||
|
||||
account_name = "FooBar"
|
||||
|
||||
{:ok, lv, _html} = live(conn, ~p"/sign_up")
|
||||
|
||||
email = Fixtures.Auth.email()
|
||||
|
||||
attrs = %{
|
||||
account: %{name: account_name},
|
||||
actor: %{name: "John Doe"},
|
||||
email: " " <> email <> " "
|
||||
}
|
||||
|
||||
Bypass.open()
|
||||
|> Domain.Mocks.Stripe.mock_create_customer_endpoint(%{
|
||||
id: Ecto.UUID.generate(),
|
||||
name: account_name
|
||||
})
|
||||
|> Domain.Mocks.Stripe.mock_create_subscription_endpoint()
|
||||
|
||||
lv
|
||||
|> form("form", registration: attrs)
|
||||
|> render_submit()
|
||||
|
||||
account = Repo.one(Domain.Accounts.Account)
|
||||
assert account.name == account_name
|
||||
assert account.metadata.stripe.customer_id
|
||||
assert account.metadata.stripe.billing_email == email
|
||||
|
||||
identity = Repo.one(Domain.Auth.Identity)
|
||||
assert identity.account_id == account.id
|
||||
assert identity.provider_identifier == email
|
||||
end
|
||||
|
||||
test "allows whitelisted domains to create new account", %{conn: conn} do
|
||||
whitelisted_domain = "example.com"
|
||||
Domain.Config.put_env_override(:outbound_email_adapter_configured?, true)
|
||||
@@ -175,7 +211,7 @@ defmodule Web.Live.SignUpTest do
|
||||
|> form("form", registration: attrs)
|
||||
|> render_submit()
|
||||
|> form_validation_errors() == %{
|
||||
"registration[email]" => ["has invalid format"]
|
||||
"registration[email]" => ["is an invalid email address"]
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user