This commit is contained in:
delete 2026-06-10 20:51:17 +03:00
commit b15b95781c
108 changed files with 14802 additions and 0 deletions

113
internal/http/router.go Normal file
View file

@ -0,0 +1,113 @@
package httpserver
import (
"log/slog"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"update_server/internal/apikeys"
authservice "update_server/internal/auth"
"update_server/internal/config"
"update_server/internal/db"
"update_server/internal/releases"
)
type handler struct {
config config.Config
store *db.Store
logger *slog.Logger
renderer *Renderer
auth *authservice.Service
apiKeys *apikeys.Service
releases *releases.Service
loginRateLimiter *rateLimitStore
clientRateLimiter *rateLimitStore
}
func NewRouter(cfg config.Config, logger *slog.Logger, renderer *Renderer, store *db.Store, auth *authservice.Service, apiKeyService *apikeys.Service, releaseService *releases.Service) http.Handler {
h := &handler{
config: cfg,
store: store,
logger: logger,
renderer: renderer,
auth: auth,
apiKeys: apiKeyService,
releases: releaseService,
loginRateLimiter: newRateLimitStore(cfg.LoginRateLimitPerMinute, cfg.LoginRateLimitBurst),
clientRateLimiter: newRateLimitStore(cfg.ClientRateLimitPerMinute, cfg.ClientRateLimitBurst),
}
router := chi.NewRouter()
router.Use(middleware.RequestID)
if cfg.TrustProxyHeaders {
router.Use(middleware.RealIP)
}
router.Use(requestLogger(logger))
router.Use(middleware.Recoverer)
router.Use(middleware.StripSlashes)
router.Use(securityHeaders(cfg))
router.Get("/healthz", h.health)
router.Handle("/static/*", http.StripPrefix("/static/", http.FileServer(http.Dir(cfg.StaticDir))))
router.Get("/", h.home)
router.Route("/admin", func(r chi.Router) {
r.Use(adminResponseHeaders)
r.Use(h.adminCSRF)
r.Get("/login", h.adminLoginForm)
r.With(h.loginRateLimit).Post("/login", h.adminLogin)
r.Group(func(r chi.Router) {
r.Use(h.requireAuthenticatedSession)
r.Use(h.requireRole(db.UserRoleAdmin))
r.Get("/", h.adminHome)
r.Post("/logout", h.adminLogout)
r.Get("/projects", h.adminProjects)
r.Get("/projects/new", h.adminProjectNew)
r.Post("/projects", h.adminProjectCreate)
r.Get("/projects/{projectID}", h.adminProjectDetail)
r.Post("/projects/{projectID}", h.adminProjectUpdate)
r.Post("/projects/{projectID}/archive", h.adminProjectArchive)
r.Post("/projects/{projectID}/tags", h.adminProjectAttachTag)
r.Post("/projects/{projectID}/tags/{tagID}/detach", h.adminProjectDetachTag)
r.Post("/projects/{projectID}/releases", h.adminProjectUploadRelease)
r.Get("/tags", h.adminTags)
r.Get("/tags/new", h.adminTagNew)
r.Post("/tags", h.adminTagCreate)
r.Get("/tags/{tagID}", h.adminTagDetail)
r.Post("/tags/{tagID}", h.adminTagUpdate)
r.Post("/tags/{tagID}/delete", h.adminTagDelete)
r.Get("/api-keys", h.adminAPIKeys)
r.Get("/api-keys/new", h.adminAPIKeyNew)
r.Post("/api-keys", h.adminAPIKeyCreate)
r.Get("/api-keys/{apiKeyID}", h.adminAPIKeyDetail)
r.Post("/api-keys/{apiKeyID}", h.adminAPIKeyUpdate)
r.Post("/api-keys/{apiKeyID}/activate", h.adminAPIKeyToggleActive)
})
})
router.Route("/api", func(r chi.Router) {
r.Route("/v1", func(r chi.Router) {
r.Use(apiResponseHeaders)
r.Get("/", h.apiIndex)
r.Group(func(r chi.Router) {
r.Use(protectedAPIResponseHeaders)
r.Use(h.clientAPIRateLimit)
r.Use(h.requireAPIKey)
r.Use(h.requireAPIKeyPermission(apikeys.PermissionDownload))
r.Get("/projects", h.apiAccessibleProjects)
r.Get("/projects/{projectSlug}/releases/latest", h.apiLatestRelease)
r.Get("/releases/{releaseID}", h.apiReleaseMetadata)
r.Get("/releases/{releaseID}/download", h.apiReleaseDownload)
})
})
})
return router
}