diff --git a/lib/towerops_web/live/equipment_live/form.ex b/lib/towerops_web/live/equipment_live/form.ex index a8df7f7a..4793fd60 100644 --- a/lib/towerops_web/live/equipment_live/form.ex +++ b/lib/towerops_web/live/equipment_live/form.ex @@ -199,8 +199,16 @@ defmodule ToweropsWeb.EquipmentLive.Form do end @spec normalize_port(integer() | String.t() | any()) :: integer() - defp normalize_port(port) when is_integer(port), do: port - defp normalize_port(port) when is_binary(port), do: String.to_integer(port) + defp normalize_port(port) when is_integer(port) and port >= 1 and port <= 65_535, do: port + defp normalize_port(port) when is_integer(port), do: 161 + + defp normalize_port(port) when is_binary(port) do + case Integer.parse(port) do + {parsed_port, ""} when parsed_port >= 1 and parsed_port <= 65_535 -> parsed_port + _ -> 161 + end + end + defp normalize_port(_), do: 161 @spec test_snmp_connection(%{ @@ -210,17 +218,50 @@ defmodule ToweropsWeb.EquipmentLive.Form do snmp_port: integer() }) :: %{success: boolean(), message: String.t()} defp test_snmp_connection(config) do - case Snmp.test_connection( - config.ip_address, - config.snmp_community, - config.snmp_version, - config.snmp_port - ) do - {:ok, message} -> - %{success: true, message: message} + # Validate IP address before testing + case validate_test_snmp_input(config) do + :ok -> + case Snmp.test_connection( + config.ip_address, + config.snmp_community, + config.snmp_version, + config.snmp_port + ) do + {:ok, message} -> + %{success: true, message: message} - {:error, reason} -> - %{success: false, message: "Connection failed: #{inspect(reason)}"} + {:error, reason} -> + %{success: false, message: "Connection failed: #{inspect(reason)}"} + end + + {:error, message} -> + %{success: false, message: message} + end + end + + @spec validate_test_snmp_input(%{ + ip_address: String.t() | nil, + snmp_community: String.t() | nil, + snmp_version: String.t() | nil, + snmp_port: integer() + }) :: :ok | {:error, String.t()} + defp validate_test_snmp_input(%{ip_address: nil}) do + {:error, "IP address is required"} + end + + defp validate_test_snmp_input(%{snmp_community: nil}) do + {:error, "SNMP community string is required"} + end + + defp validate_test_snmp_input(%{snmp_community: ""}) do + {:error, "SNMP community string is required"} + end + + defp validate_test_snmp_input(%{ip_address: ip}) do + # Validate IP address format using Erlang's inet module + case ip |> String.to_charlist() |> :inet.parse_address() do + {:ok, _} -> :ok + {:error, _} -> {:error, "Invalid IP address format"} end end end diff --git a/lib/towerops_web/user_auth.ex b/lib/towerops_web/user_auth.ex index 3e9224c3..a3fce358 100644 --- a/lib/towerops_web/user_auth.ex +++ b/lib/towerops_web/user_auth.ex @@ -16,7 +16,7 @@ defmodule ToweropsWeb.UserAuth do @remember_me_options [ sign: true, max_age: @max_cookie_age_in_days * 24 * 60 * 60, - same_site: "Lax" + same_site: "Towerops" ] # How old the session token should be before a new one is issued. When a request is made diff --git a/mix.exs b/mix.exs index 233e8d47..47c6fb65 100644 --- a/mix.exs +++ b/mix.exs @@ -71,7 +71,8 @@ defmodule Towerops.MixProject do {:styler, "~> 1.10", only: [:dev, :test], runtime: false}, {:mix_test_watch, "~> 1.0", only: [:dev, :test], runtime: false}, {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}, - {:credo, "~> 1.7", only: [:dev, :test], runtime: false} + {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, + {:sobelow, "~> 0.14.1", only: [:dev, :test], runtime: false} ] end diff --git a/mix.lock b/mix.lock index b61f1c0b..c54481b0 100644 --- a/mix.lock +++ b/mix.lock @@ -46,6 +46,7 @@ "postgrex": {:hex, :postgrex, "0.21.1", "2c5cc830ec11e7a0067dd4d623c049b3ef807e9507a424985b8dcf921224cd88", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "27d8d21c103c3cc68851b533ff99eef353e6a0ff98dc444ea751de43eb48bdac"}, "req": {:hex, :req, "0.5.16", "99ba6a36b014458e52a8b9a0543bfa752cb0344b2a9d756651db1281d4ba4450", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "974a7a27982b9b791df84e8f6687d21483795882a7840e8309abdbe08bb06f09"}, "snmpkit": {:hex, :snmpkit, "1.3.19", "b09c38cea619a0a67d4fb0f3bfa3b9b749d42c400c2e7bd9446fef82f0d728a7", [:mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}, {:yaml_elixir, "~> 2.9", [hex: :yaml_elixir, repo: "hexpm", optional: true]}], "hexpm", "b05c1f3911204c4d781234187a6f1350c369fcffe2058a85b49735b1259eb973"}, + "sobelow": {:hex, :sobelow, "0.14.1", "2f81e8632f15574cba2402bcddff5497b413c01e6f094bc0ab94e83c2f74db81", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8fac9a2bd90fdc4b15d6fca6e1608efb7f7c600fa75800813b794ee9364c87f2"}, "styler": {:hex, :styler, "1.10.0", "343f1f7bb19a8893c2841a9ae90665b68d2edf6cc37b964a5099e60c78815c2e", [:mix], [], "hexpm", "6a78876611869466139e63722df4cbbb56b18a842d88c19f23ca844d914ad91a"}, "swoosh": {:hex, :swoosh, "1.19.9", "4eb2c471b8cf06adbdcaa1d57a0ad53c0ed9348ce8586a06cc491f9f0dbcb553", [:mix], [{:bandit, ">= 1.0.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:idna, "~> 6.0", [hex: :idna, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mua, "~> 0.2.3", [hex: :mua, repo: "hexpm", optional: true]}, {:multipart, "~> 0.4", [hex: :multipart, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:req, "~> 0.5.10 or ~> 0.6 or ~> 1.0", [hex: :req, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "516898263a64925c31723c56bc7999a26e97b04e869707f681f4c9bca7ee1688"}, "table_rex": {:hex, :table_rex, "4.1.0", "fbaa8b1ce154c9772012bf445bfb86b587430fb96f3b12022d3f35ee4a68c918", [:mix], [], "hexpm", "95932701df195d43bc2d1c6531178fc8338aa8f38c80f098504d529c43bc2601"},