76 lines
1.9 KiB
Elixir
76 lines
1.9 KiB
Elixir
defmodule MoundHuntersWeb.Plugs.BoundsCheck do
|
|
@moduledoc """
|
|
Plug to validate that coordinates are within Ohio boundaries.
|
|
Applies to tile requests but not to geometry sharing API.
|
|
"""
|
|
import Plug.Conn
|
|
require Logger
|
|
|
|
def init(opts), do: opts
|
|
|
|
def call(conn, _opts) do
|
|
# Skip bounds check for non-tile endpoints
|
|
if skip_bounds_check?(conn.request_path) do
|
|
conn
|
|
else
|
|
check_bounds(conn)
|
|
end
|
|
end
|
|
|
|
defp skip_bounds_check?(path) do
|
|
# Skip bounds check for geometry API and static files
|
|
String.starts_with?(path, "/api/share") or
|
|
String.starts_with?(path, "/static/") or
|
|
path == "/"
|
|
end
|
|
|
|
defp check_bounds(conn) do
|
|
cond do
|
|
# Check query params for tile request
|
|
conn.query_params["lat"] != nil and conn.query_params["lng"] != nil ->
|
|
check_query_params(conn)
|
|
|
|
# For tile file serving, we assume tiles in storage are valid
|
|
# (they were validated when created)
|
|
String.starts_with?(conn.request_path, "/tiles/") ->
|
|
conn
|
|
|
|
true ->
|
|
conn
|
|
end
|
|
end
|
|
|
|
defp check_query_params(conn) do
|
|
with {:ok, lat} <- parse_float(conn.query_params["lat"]),
|
|
{:ok, lng} <- parse_float(conn.query_params["lng"]),
|
|
:ok <- MoundHunters.Boundary.check_bounds(lat, lng) do
|
|
conn
|
|
else
|
|
{:error, :invalid_number} ->
|
|
send_error(conn, 400, "Invalid coordinate format")
|
|
|
|
{:error, reason} ->
|
|
send_error(conn, 400, reason)
|
|
end
|
|
end
|
|
|
|
defp parse_float(str) when is_binary(str) do
|
|
case Float.parse(str) do
|
|
{num, ""} -> {:ok, num}
|
|
_ -> {:error, :invalid_number}
|
|
end
|
|
end
|
|
|
|
defp parse_float(_), do: {:error, :invalid_number}
|
|
|
|
defp send_error(conn, status, message) do
|
|
Logger.warning("Bounds check failed: #{message}")
|
|
|
|
conn
|
|
|> put_private(:error_message, message)
|
|
|> put_resp_content_type("application/json")
|
|
|> send_resp(status, Jason.encode!(%{error: message}))
|
|
|> halt()
|
|
end
|
|
end
|