towerops/lib/towerops_web/router.ex

308 lines
9.5 KiB
Elixir

defmodule ToweropsWeb.Router do
@moduledoc false
use ToweropsWeb, :router
use Honeybadger.Plug
import Oban.Web.Router
import Phoenix.LiveDashboard.Router
import ToweropsWeb.UserAuth
alias ToweropsWeb.Api.V1
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_live_flash
plug :put_root_layout, html: {ToweropsWeb.Layouts, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
plug :fetch_current_scope_for_user
plug ToweropsWeb.Plugs.UpdateSessionActivity
plug :store_return_to_for_liveview
plug ToweropsWeb.Plugs.DetectEUUser
plug ToweropsWeb.Plugs.CheckPolicyConsent
end
pipeline :api do
plug :accepts, ["json"]
end
pipeline :mobile_api do
plug :accepts, ["json"]
plug ToweropsWeb.Plugs.MobileAuth
end
pipeline :api_v1 do
plug :accepts, ["json"]
plug ToweropsWeb.Plugs.ApiAuth
end
# Health check endpoint for Kubernetes probes (no authentication required)
scope "/", ToweropsWeb do
get "/health", HealthController, :index
get "/health/time", HealthController, :time
end
scope "/", ToweropsWeb do
pipe_through :browser
get "/", PageController, :home
get "/privacy", PageController, :privacy
get "/terms", PageController, :terms
get "/docs/api", ApiDocsController, :index
live "/help", HelpLive.Index, :index
end
# Account API routes (requires browser authentication)
scope "/api/v1/account", ToweropsWeb.Api do
pipe_through [:browser, :require_authenticated_user]
get "/data", AccountDataController, :show
end
# Agent communication via WebSocket channel at /socket/agent
# See ToweropsWeb.AgentChannel for implementation
# Mobile Auth API routes (no authentication required for login flow)
scope "/api/v1/mobile/auth", ToweropsWeb.Api do
pipe_through :api
post "/qr/verify", MobileAuthController, :verify_qr_token
post "/qr/complete", MobileAuthController, :complete_qr_login
end
# Mobile API routes (requires mobile authentication)
scope "/api/v1/mobile", ToweropsWeb.Api do
pipe_through :mobile_api
# Auth session management
get "/auth/session", MobileAuthController, :get_session
delete "/auth/session", MobileAuthController, :revoke_session
# Data endpoints
get "/organizations", MobileController, :list_organizations
get "/organizations/:organization_id/sites", MobileController, :list_sites
get "/organizations/:organization_id/devices", MobileController, :list_devices
get "/organizations/:organization_id/alerts", MobileController, :list_alerts
get "/devices/:id", MobileController, :get_equipment
end
# API v1 routes (requires API token authentication)
scope "/api/v1", V1 do
pipe_through :api_v1
resources "/sites", SitesController, except: [:new, :edit]
resources "/devices", DevicesController, except: [:new, :edit]
end
# Admin API routes (requires superuser API token)
scope "/admin/api", V1 do
pipe_through :api_v1
# MIB file management
get "/mibs", MibController, :index
post "/mibs", MibController, :upload
delete "/mibs/:vendor", MibController, :delete
# GeoIP database management
post "/geoip/import", GeoipController, :import_database
end
# WebAuthn API routes
scope "/api/webauthn", ToweropsWeb do
pipe_through [:browser]
post "/authentication/challenge", UserCredentialController, :authentication_challenge
post "/authenticate", UserCredentialController, :authenticate
end
scope "/api/webauthn", ToweropsWeb do
pipe_through [:browser, :require_authenticated_user]
post "/registration/challenge", UserCredentialController, :registration_challenge
post "/register", UserCredentialController, :register
end
# Enable LiveDashboard in production with authentication
scope "/dashboard" do
pipe_through [:browser, :require_authenticated_user, :require_superuser]
live_dashboard "/",
metrics: ToweropsWeb.Telemetry,
ecto_repos: [Towerops.Repo],
ecto_psql_extras_options: [
# Exclude TimescaleDB internal tables from constraint checks
missing_fk_constraints: [
exclude: ~r/^_(hyper_|materialized_hypertable_)/
]
]
end
# Enable Oban Web (superuser only)
scope "/" do
pipe_through [:browser, :require_authenticated_user, :require_superuser]
oban_dashboard("/oban")
end
# Enable Swoosh mailbox preview in development
if Application.compile_env(:towerops, :dev_routes) do
scope "/dev" do
pipe_through :browser
forward "/mailbox", Plug.Swoosh.MailboxPreview
end
end
## Authentication routes
scope "/", ToweropsWeb do
pipe_through [:browser, :redirect_if_user_is_authenticated]
get "/users/register", UserRegistrationController, :new
post "/users/register", UserRegistrationController, :create
end
scope "/", ToweropsWeb do
pipe_through [:browser, :require_authenticated_user]
get "/users/settings/confirm-email/:token", UserSettingsController, :confirm_email
delete "/users/credentials/:id", UserCredentialController, :delete
end
scope "/", ToweropsWeb do
pipe_through [:browser]
get "/users/log-in", UserSessionController, :new
get "/users/log-in/:token", UserSessionController, :confirm
post "/users/log-in", UserSessionController, :create
delete "/users/log-out", UserSessionController, :delete
end
## Admin routes (superuser only)
scope "/", ToweropsWeb do
pipe_through [:browser, :require_authenticated_user, :require_superuser]
post "/admin/impersonate/:user_id", AdminController, :start_impersonate
delete "/admin/impersonate", AdminController, :stop_impersonate
end
live_session :require_superuser,
on_mount: [
{ToweropsWeb.UserAuth, :load_cookie_consent},
{ToweropsWeb.UserAuth, :require_authenticated_user},
{ToweropsWeb.UserAuth, :require_totp_enrollment},
{ToweropsWeb.UserAuth, :require_superuser},
{ToweropsWeb.UserAuth, :handle_policy_consent}
] do
scope "/admin", ToweropsWeb.Admin do
pipe_through [:browser, :require_authenticated_user, :require_superuser]
live "/", DashboardLive, :index
live "/users", UserLive.Index, :index
live "/organizations", OrgLive.Index, :index
end
end
## Organization routes
live_session :require_sudo_mode,
on_mount: [
{ToweropsWeb.UserAuth, :load_cookie_consent},
{ToweropsWeb.UserAuth, :require_authenticated_user},
{ToweropsWeb.UserAuth, :require_totp_enrollment},
{ToweropsWeb.UserAuth, :require_sudo_mode},
{ToweropsWeb.UserAuth, :handle_policy_consent}
] do
scope "/", ToweropsWeb do
pipe_through [:browser, :require_authenticated_user]
live "/users/settings", UserSettingsLive, :index
live "/users/my-data", AccountLive.MyData, :index
end
end
# TOTP enrollment page - requires auth but NOT TOTP (since user is enrolling)
live_session :totp_enrollment,
on_mount: [
{ToweropsWeb.UserAuth, :load_cookie_consent},
{ToweropsWeb.UserAuth, :require_authenticated_user}
] do
scope "/", ToweropsWeb do
pipe_through [:browser, :require_authenticated_user]
live "/account/totp-enrollment", AccountLive.TotpEnrollment, :index
end
end
live_session :require_authenticated_user,
on_mount: [
{ToweropsWeb.UserAuth, :load_cookie_consent},
{ToweropsWeb.UserAuth, :require_authenticated_user},
{ToweropsWeb.UserAuth, :require_totp_enrollment},
{ToweropsWeb.UserAuth, :handle_policy_consent}
] do
scope "/", ToweropsWeb do
pipe_through [:browser, :require_authenticated_user]
live "/mobile/qr-login", MobileQRLive, :index
live "/orgs", OrgLive.Index, :index
live "/orgs/new", OrgLive.New, :new
end
end
live_session :require_authenticated_user_and_organization,
on_mount: [
{ToweropsWeb.UserAuth, :load_cookie_consent},
{ToweropsWeb.UserAuth, :require_authenticated_user},
{ToweropsWeb.UserAuth, :require_totp_enrollment},
{ToweropsWeb.UserAuth, :load_current_organization},
{ToweropsWeb.UserAuth, :handle_policy_consent}
] do
scope "/orgs/:org_slug", ToweropsWeb do
pipe_through [:browser, :require_authenticated_user, :load_current_organization]
live "/", DashboardLive, :index
live "/settings", Org.SettingsLive, :index
end
end
live_session :require_authenticated_user_with_default_org,
on_mount: [
{ToweropsWeb.UserAuth, :load_cookie_consent},
{ToweropsWeb.UserAuth, :require_authenticated_user},
{ToweropsWeb.UserAuth, :require_totp_enrollment},
{ToweropsWeb.UserAuth, :load_default_organization},
{ToweropsWeb.UserAuth, :handle_policy_consent}
] do
scope "/", ToweropsWeb do
pipe_through [:browser, :require_authenticated_user]
# Alert routes
live "/alerts", AlertLive.Index, :index
# Agent routes
live "/agents", AgentLive.Index, :index
live "/agents/:id/edit", AgentLive.Edit, :edit
live "/agents/:id", AgentLive.Show, :show
# Site routes
live "/sites", SiteLive.Index, :index
live "/sites/new", SiteLive.Form, :new
live "/sites/:id", SiteLive.Show, :show
live "/sites/:id/edit", SiteLive.Form, :edit
# Device routes
live "/devices", DeviceLive.Index, :index
live "/devices/new", DeviceLive.Form, :new
live "/devices/:id", DeviceLive.Show, :show
live "/devices/:id/edit", DeviceLive.Form, :edit
live "/devices/:id/graph/:sensor_type", GraphLive.Show, :show
# Network map route
live "/network-map", NetworkMapLive, :index
end
end
end