207 lines
5.6 KiB
Go
207 lines
5.6 KiB
Go
package auth
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
|
|
"github.com/example/remote-access-platform/backend/internal/platform/httpx"
|
|
"github.com/example/remote-access-platform/backend/internal/platform/module"
|
|
)
|
|
|
|
type Module struct {
|
|
service *Service
|
|
}
|
|
|
|
func NewModule(deps module.Dependencies, service *Service) *Module {
|
|
return &Module{service: service}
|
|
}
|
|
|
|
func (m *Module) Name() string {
|
|
return "auth"
|
|
}
|
|
|
|
func (m *Module) RegisterRoutes(router chi.Router) {
|
|
router.Route("/installation", func(r chi.Router) {
|
|
r.Get("/status", m.handleInstallationStatus)
|
|
r.Post("/bootstrap-owner", m.handleBootstrapOwner)
|
|
})
|
|
router.Route("/auth", func(r chi.Router) {
|
|
r.Get("/ui/login", m.handleLoginHTMLPage)
|
|
r.Post("/ui/login", m.handleLoginHTML)
|
|
r.Get("/ui/vpn-download", m.handleVPNDownloadHTML)
|
|
r.Post("/login", m.handleLogin)
|
|
r.Post("/refresh", m.handleRefresh)
|
|
r.Post("/sessions/revoke", m.handleRevokeAuthSession)
|
|
r.Get("/devices", m.handleTrustedDevices)
|
|
r.Post("/devices/{deviceID}/revoke", m.handleRevokeTrustedDevice)
|
|
})
|
|
router.Route("/users", func(r chi.Router) {
|
|
r.Get("/", m.handleListUsers)
|
|
r.Post("/", m.handleCreateUser)
|
|
})
|
|
}
|
|
|
|
func (m *Module) handleInstallationStatus(w http.ResponseWriter, r *http.Request) {
|
|
status, err := m.service.InstallationStatus(r.Context())
|
|
if err != nil {
|
|
statusCode, message := m.service.MapError(err)
|
|
httpx.WriteError(w, statusCode, message)
|
|
return
|
|
}
|
|
httpx.WriteJSON(w, http.StatusOK, map[string]any{"installation": status})
|
|
}
|
|
|
|
func (m *Module) handleBootstrapOwner(w http.ResponseWriter, r *http.Request) {
|
|
var cmd BootstrapOwnerCommand
|
|
if err := json.NewDecoder(r.Body).Decode(&cmd); err != nil {
|
|
httpx.WriteError(w, http.StatusBadRequest, "invalid installation bootstrap payload")
|
|
return
|
|
}
|
|
result, err := m.service.BootstrapOwner(r.Context(), cmd)
|
|
if err != nil {
|
|
status, message := m.service.MapError(err)
|
|
httpx.WriteError(w, status, message)
|
|
return
|
|
}
|
|
httpx.WriteJSON(w, http.StatusCreated, result)
|
|
}
|
|
|
|
func (m *Module) handleLogin(w http.ResponseWriter, r *http.Request) {
|
|
var cmd LoginCommand
|
|
if err := json.NewDecoder(r.Body).Decode(&cmd); err != nil {
|
|
httpx.WriteError(w, http.StatusBadRequest, "invalid login payload")
|
|
return
|
|
}
|
|
|
|
result, err := m.service.Login(r.Context(), cmd)
|
|
if err != nil {
|
|
status, message := m.service.MapError(err)
|
|
httpx.WriteError(w, status, message)
|
|
return
|
|
}
|
|
|
|
httpx.WriteJSON(w, http.StatusOK, result)
|
|
}
|
|
|
|
func (m *Module) handleListUsers(w http.ResponseWriter, r *http.Request) {
|
|
actorUserID := r.URL.Query().Get("actor_user_id")
|
|
users, err := m.service.ListUsers(r.Context(), actorUserID)
|
|
if err != nil {
|
|
status, message := m.service.MapError(err)
|
|
httpx.WriteError(w, status, message)
|
|
return
|
|
}
|
|
httpx.WriteJSON(w, http.StatusOK, map[string]any{"users": users})
|
|
}
|
|
|
|
func (m *Module) handleCreateUser(w http.ResponseWriter, r *http.Request) {
|
|
var cmd CreateUserCommand
|
|
if err := json.NewDecoder(r.Body).Decode(&cmd); err != nil {
|
|
httpx.WriteError(w, http.StatusBadRequest, "invalid user payload")
|
|
return
|
|
}
|
|
user, err := m.service.CreateUser(r.Context(), cmd)
|
|
if err != nil {
|
|
status, message := m.service.MapError(err)
|
|
httpx.WriteError(w, status, message)
|
|
return
|
|
}
|
|
httpx.WriteJSON(w, http.StatusCreated, map[string]any{"user": user})
|
|
}
|
|
|
|
func (m *Module) handleRefresh(w http.ResponseWriter, r *http.Request) {
|
|
var cmd RefreshCommand
|
|
if err := json.NewDecoder(r.Body).Decode(&cmd); err != nil {
|
|
httpx.WriteError(w, http.StatusBadRequest, "invalid refresh payload")
|
|
return
|
|
}
|
|
|
|
result, err := m.service.Refresh(r.Context(), cmd)
|
|
if err != nil {
|
|
status, message := m.service.MapError(err)
|
|
httpx.WriteError(w, status, message)
|
|
return
|
|
}
|
|
|
|
httpx.WriteJSON(w, http.StatusOK, result)
|
|
}
|
|
|
|
func (m *Module) handleRevokeAuthSession(w http.ResponseWriter, r *http.Request) {
|
|
var cmd RevokeAuthSessionCommand
|
|
if err := json.NewDecoder(r.Body).Decode(&cmd); err != nil {
|
|
httpx.WriteError(w, http.StatusBadRequest, "invalid auth session revoke payload")
|
|
return
|
|
}
|
|
|
|
if err := m.service.RevokeAuthSession(r.Context(), cmd); err != nil {
|
|
status, message := m.service.MapError(err)
|
|
httpx.WriteError(w, status, message)
|
|
return
|
|
}
|
|
|
|
httpx.WriteJSON(w, http.StatusAccepted, map[string]any{
|
|
"status": "revoked",
|
|
"message": httpx.NewMessage(
|
|
"auth.session.revoked",
|
|
"status.auth.session.revoked",
|
|
"Auth session revoked.",
|
|
nil,
|
|
"",
|
|
),
|
|
})
|
|
}
|
|
|
|
func (m *Module) handleTrustedDevices(w http.ResponseWriter, r *http.Request) {
|
|
userID := r.URL.Query().Get("user_id")
|
|
if userID == "" {
|
|
httpx.WriteError(w, http.StatusBadRequest, "user_id is required")
|
|
return
|
|
}
|
|
|
|
devices, err := m.service.ListTrustedDevices(r.Context(), userID)
|
|
if err != nil {
|
|
status, message := m.service.MapError(err)
|
|
httpx.WriteError(w, status, message)
|
|
return
|
|
}
|
|
|
|
httpx.WriteJSON(w, http.StatusOK, map[string]any{
|
|
"devices": devices,
|
|
})
|
|
}
|
|
|
|
func (m *Module) handleRevokeTrustedDevice(w http.ResponseWriter, r *http.Request) {
|
|
var payload struct {
|
|
UserID string `json:"user_id"`
|
|
Reason string `json:"reason"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
|
httpx.WriteError(w, http.StatusBadRequest, "invalid device revoke payload")
|
|
return
|
|
}
|
|
|
|
err := m.service.RevokeTrustedDevice(r.Context(), RevokeDeviceCommand{
|
|
UserID: payload.UserID,
|
|
DeviceID: chi.URLParam(r, "deviceID"),
|
|
Reason: payload.Reason,
|
|
})
|
|
if err != nil {
|
|
status, message := m.service.MapError(err)
|
|
httpx.WriteError(w, status, message)
|
|
return
|
|
}
|
|
|
|
httpx.WriteJSON(w, http.StatusAccepted, map[string]any{
|
|
"status": "revoked",
|
|
"message": httpx.NewMessage(
|
|
"auth.device.revoked",
|
|
"status.auth.device.revoked",
|
|
"Trusted device revoked.",
|
|
nil,
|
|
"",
|
|
),
|
|
})
|
|
}
|