- LIKE wildcard injection: sanitize %, _ in search queries (devices, sites, gaiia) - Jason.decode! → Jason.decode with error handling for untrusted input - inspect() leak: replace with generic error messages, log details server-side - SSRF protection: URL validator blocks private IPs, localhost, non-HTTP schemes - SSRF validation added to HTTP monitoring executor and integration credentials - GraphQL complexity limits: always applied, not just in prod - GraphQL introspection: also check GET query params, not just body - Stripe webhook: explicit nil/empty checks for signature and body - Cookie security: secure flag for session (prod), http_only+secure for remember_me - Honeybadger API key: read from env var with fallback - String.to_integer → Integer.parse with fallback for URL params - String.to_atom → whitelist map for HTTP methods - Gaiia webhook: remove secret_len and expected signature from log - Admin API: add rate limiting pipeline - to_atom_keys: per-key fallback instead of all-or-nothing rescue
84 lines
2.5 KiB
Elixir
84 lines
2.5 KiB
Elixir
defmodule ToweropsWeb.EscalationPolicyLive.Form do
|
|
@moduledoc false
|
|
use ToweropsWeb, :live_view
|
|
|
|
alias Towerops.OnCall
|
|
alias Towerops.OnCall.EscalationPolicy
|
|
|
|
@impl true
|
|
def mount(_params, _session, socket) do
|
|
{:ok, assign(socket, :active_page, "schedules")}
|
|
end
|
|
|
|
@impl true
|
|
def handle_params(params, _url, socket) do
|
|
case socket.assigns.live_action do
|
|
:new ->
|
|
policy = %EscalationPolicy{}
|
|
changeset = EscalationPolicy.changeset(policy, %{})
|
|
|
|
{:noreply,
|
|
socket
|
|
|> assign(:page_title, t("New Escalation Policy"))
|
|
|> assign(:policy, policy)
|
|
|> assign(:form, to_form(changeset))}
|
|
|
|
:edit ->
|
|
org_id = socket.assigns.current_scope.organization.id
|
|
policy = OnCall.get_escalation_policy!(params["id"], org_id)
|
|
changeset = EscalationPolicy.changeset(policy, %{})
|
|
|
|
{:noreply,
|
|
socket
|
|
|> assign(:page_title, t("Edit Escalation Policy"))
|
|
|> assign(:policy, policy)
|
|
|> assign(:form, to_form(changeset))}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_event("validate", %{"escalation_policy" => params}, socket) do
|
|
changeset =
|
|
socket.assigns.policy
|
|
|> EscalationPolicy.changeset(params)
|
|
|> Map.put(:action, :validate)
|
|
|
|
{:noreply, assign(socket, :form, to_form(changeset))}
|
|
end
|
|
|
|
def handle_event("save", %{"escalation_policy" => params}, socket) do
|
|
org_id = socket.assigns.current_scope.organization.id
|
|
params = Map.put(params, "organization_id", org_id)
|
|
|
|
case socket.assigns.live_action do
|
|
:new -> save_policy(socket, :create, params)
|
|
:edit -> save_policy(socket, :update, params)
|
|
end
|
|
end
|
|
|
|
defp save_policy(socket, :create, params) do
|
|
case OnCall.create_escalation_policy(params) do
|
|
{:ok, policy} ->
|
|
{:noreply,
|
|
socket
|
|
|> put_flash(:info, t("Escalation policy created"))
|
|
|> push_navigate(to: ~p"/schedules/escalation-policies/#{policy.id}")}
|
|
|
|
{:error, changeset} ->
|
|
{:noreply, assign(socket, :form, to_form(changeset))}
|
|
end
|
|
end
|
|
|
|
defp save_policy(socket, :update, params) do
|
|
case OnCall.update_escalation_policy(socket.assigns.policy, params) do
|
|
{:ok, policy} ->
|
|
{:noreply,
|
|
socket
|
|
|> put_flash(:info, t("Escalation policy updated"))
|
|
|> push_navigate(to: ~p"/schedules/escalation-policies/#{policy.id}")}
|
|
|
|
{:error, changeset} ->
|
|
{:noreply, assign(socket, :form, to_form(changeset))}
|
|
end
|
|
end
|
|
end
|