mirror of
				https://github.com/NginxProxyManager/nginx-proxy-manager.git
				synced 2025-10-31 15:53:33 +00:00 
			
		
		
		
	- Certificate renewal is just a re-request as it's forced already - Rejig the routes for readability - Added Server Side Events so that the UI would invalidate the cache when changes happen on the backend, such as certs being provided or failing - Added a SSE Token, which has the same shelf life as normal token but can't be used interchangeably. The reason for this is, the SSE endpoint needs a token for auth as a Query param, so it would be stored in log files. If someone where to get a hold of that, it's pretty useless as it can't be used to change anything, only to listen for events until it expires - Added test endpoint for SSE testing only availabe in debug mode
		
			
				
	
	
		
			336 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			336 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package api
 | |
| 
 | |
| import (
 | |
| 	"net/http"
 | |
| 	"time"
 | |
| 
 | |
| 	"npm/internal/api/handler"
 | |
| 	"npm/internal/api/middleware"
 | |
| 	"npm/internal/api/schema"
 | |
| 	"npm/internal/config"
 | |
| 	"npm/internal/entity/accesslist"
 | |
| 	"npm/internal/entity/certificate"
 | |
| 	"npm/internal/entity/certificateauthority"
 | |
| 	"npm/internal/entity/dnsprovider"
 | |
| 	"npm/internal/entity/host"
 | |
| 	"npm/internal/entity/nginxtemplate"
 | |
| 	"npm/internal/entity/setting"
 | |
| 	"npm/internal/entity/stream"
 | |
| 	"npm/internal/entity/upstream"
 | |
| 	"npm/internal/entity/user"
 | |
| 	"npm/internal/logger"
 | |
| 	"npm/internal/serverevents"
 | |
| 
 | |
| 	"github.com/go-chi/chi"
 | |
| 	chiMiddleware "github.com/go-chi/chi/middleware"
 | |
| 	"github.com/go-chi/cors"
 | |
| )
 | |
| 
 | |
| // NewRouter returns a new router object
 | |
| func NewRouter() http.Handler {
 | |
| 	// Cors
 | |
| 	cors := cors.New(cors.Options{
 | |
| 		AllowedOrigins:   []string{"*"},
 | |
| 		AllowedMethods:   []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
 | |
| 		AllowedHeaders:   []string{"Accept", "Authorization", "Content-Type", "X-Requested-With"},
 | |
| 		AllowCredentials: true,
 | |
| 		MaxAge:           300,
 | |
| 	})
 | |
| 
 | |
| 	r := chi.NewRouter()
 | |
| 	r.Use(
 | |
| 		middleware.AccessControl,
 | |
| 		middleware.Cors(r),
 | |
| 		middleware.Options(r),
 | |
| 		cors.Handler,
 | |
| 		chiMiddleware.RealIP,
 | |
| 		chiMiddleware.Recoverer,
 | |
| 		chiMiddleware.Throttle(5),
 | |
| 		middleware.PrettyPrint,
 | |
| 		middleware.Expansion,
 | |
| 		middleware.DecodeAuth(),
 | |
| 		middleware.BodyContext(),
 | |
| 	)
 | |
| 
 | |
| 	return applyRoutes(r)
 | |
| }
 | |
| 
 | |
| // applyRoutes is where the magic happens
 | |
| func applyRoutes(r chi.Router) chi.Router {
 | |
| 	middleware.AuthCacheInit()
 | |
| 	r.NotFound(handler.NotFound())
 | |
| 	r.MethodNotAllowed(handler.NotAllowed())
 | |
| 
 | |
| 	// SSE - requires a sse token as the `jwt` get parameter
 | |
| 	// Exists inside /api but it's here so that we can skip the Timeout middleware
 | |
| 	// that applies to other endpoints.
 | |
| 	r.With(middleware.EnforceSetup(true), middleware.SSEAuth).
 | |
| 		Mount("/api/sse", serverevents.Get())
 | |
| 
 | |
| 	// API
 | |
| 	r.With(chiMiddleware.Timeout(30*time.Second)).Route("/api", func(r chi.Router) {
 | |
| 		r.Get("/", handler.Health())
 | |
| 		r.Get("/schema", handler.Schema())
 | |
| 		r.With(middleware.EnforceSetup(true), middleware.Enforce("")).
 | |
| 			Get("/config", handler.Config())
 | |
| 
 | |
| 		// Tokens
 | |
| 		r.With(middleware.EnforceSetup(true)).Route("/tokens", func(r chi.Router) {
 | |
| 			r.With(middleware.EnforceRequestSchema(schema.GetToken())).
 | |
| 				Post("/", handler.NewToken())
 | |
| 			r.With(middleware.Enforce("")).
 | |
| 				Get("/", handler.RefreshToken())
 | |
| 			r.With(middleware.Enforce("")).
 | |
| 				Post("/sse", handler.NewSSEToken())
 | |
| 		})
 | |
| 
 | |
| 		// Users
 | |
| 		r.Route("/users", func(r chi.Router) {
 | |
| 			// Create - can be done in Setup stage as well
 | |
| 			r.With(middleware.Enforce(user.CapabilityUsersManage), middleware.EnforceRequestSchema(schema.CreateUser())).
 | |
| 				Post("/", handler.CreateUser())
 | |
| 
 | |
| 			// Requires Setup stage to be completed
 | |
| 			r.With(middleware.EnforceSetup(true)).Route("/", func(r chi.Router) {
 | |
| 				// Get yourself, requires a login but no other permissions
 | |
| 				r.With(middleware.Enforce("")).
 | |
| 					Get("/{userID:(?:me)}", handler.GetUser())
 | |
| 
 | |
| 				// Update yourself, requires a login but no other permissions
 | |
| 				r.With(middleware.Enforce(""), middleware.EnforceRequestSchema(schema.UpdateUser())).
 | |
| 					Put("/{userID:(?:me)}", handler.UpdateUser())
 | |
| 
 | |
| 				r.With(middleware.Enforce(user.CapabilityUsersManage)).Route("/", func(r chi.Router) {
 | |
| 					// List
 | |
| 					r.With(middleware.Enforce(user.CapabilityUsersManage), middleware.Filters(user.GetFilterSchema())).
 | |
| 						Get("/", handler.GetUsers())
 | |
| 
 | |
| 					// Specific Item
 | |
| 					r.Get("/{userID:(?:[0-9]+)}", handler.GetUser())
 | |
| 					r.Delete("/{userID:(?:[0-9]+|me)}", handler.DeleteUser())
 | |
| 
 | |
| 					// Update another user
 | |
| 					r.With(middleware.EnforceRequestSchema(schema.UpdateUser())).
 | |
| 						Put("/{userID:(?:[0-9]+)}", handler.UpdateUser())
 | |
| 				})
 | |
| 
 | |
| 				// Auth - sets passwords
 | |
| 				r.With(middleware.Enforce(""), middleware.EnforceRequestSchema(schema.SetAuth())).
 | |
| 					Post("/{userID:(?:me)}/auth", handler.SetAuth())
 | |
| 				r.With(middleware.Enforce(user.CapabilityUsersManage), middleware.EnforceRequestSchema(schema.SetAuth())).
 | |
| 					Post("/{userID:(?:[0-9]+)}/auth", handler.SetAuth())
 | |
| 			})
 | |
| 		})
 | |
| 
 | |
| 		// Only available in debug mode
 | |
| 		if config.GetLogLevel() == logger.DebugLevel {
 | |
| 			// delete users without auth
 | |
| 			r.Delete("/users", handler.DeleteUsers())
 | |
| 			// SSE test endpoints
 | |
| 			r.Post("/sse-notification", handler.TestSSENotification())
 | |
| 		}
 | |
| 
 | |
| 		// Settings
 | |
| 		r.With(middleware.EnforceSetup(true), middleware.Enforce(user.CapabilitySettingsManage)).Route("/settings", func(r chi.Router) {
 | |
| 			r.With(middleware.Filters(setting.GetFilterSchema())).
 | |
| 				Get("/", handler.GetSettings())
 | |
| 			r.Get("/{name}", handler.GetSetting())
 | |
| 			r.With(middleware.EnforceRequestSchema(schema.CreateSetting())).
 | |
| 				Post("/", handler.CreateSetting())
 | |
| 			r.With(middleware.EnforceRequestSchema(schema.UpdateSetting())).
 | |
| 				Put("/{name}", handler.UpdateSetting())
 | |
| 		})
 | |
| 
 | |
| 		// Access Lists
 | |
| 		r.With(middleware.EnforceSetup(true)).Route("/access-lists", func(r chi.Router) {
 | |
| 			// List
 | |
| 			r.With(middleware.Filters(accesslist.GetFilterSchema()), middleware.Enforce(user.CapabilityAccessListsView)).
 | |
| 				Get("/", handler.GetAccessLists())
 | |
| 
 | |
| 			// Create
 | |
| 			r.With(middleware.Enforce(user.CapabilityAccessListsManage), middleware.EnforceRequestSchema(schema.CreateAccessList())).
 | |
| 				Post("/", handler.CreateAccessList())
 | |
| 
 | |
| 			// Specific Item
 | |
| 			r.Route("/{accessListID:[0-9]+}", func(r chi.Router) {
 | |
| 				r.With(middleware.Enforce(user.CapabilityAccessListsView)).
 | |
| 					Get("/", handler.GetAccessList())
 | |
| 				r.With(middleware.Enforce(user.CapabilityAccessListsManage)).Route("/", func(r chi.Router) {
 | |
| 					r.Delete("/{accessListID:[0-9]+}", handler.DeleteAccessList())
 | |
| 					r.With(middleware.EnforceRequestSchema(schema.UpdateAccessList())).
 | |
| 						Put("/{accessListID:[0-9]+}", handler.UpdateAccessList())
 | |
| 				})
 | |
| 			})
 | |
| 		})
 | |
| 
 | |
| 		// DNS Providers
 | |
| 		r.With(middleware.EnforceSetup(true)).Route("/dns-providers", func(r chi.Router) {
 | |
| 			// List
 | |
| 			r.With(middleware.Enforce(user.CapabilityDNSProvidersView), middleware.Filters(dnsprovider.GetFilterSchema())).
 | |
| 				Get("/", handler.GetDNSProviders())
 | |
| 
 | |
| 			// Create
 | |
| 			r.With(middleware.Enforce(user.CapabilityDNSProvidersManage), middleware.EnforceRequestSchema(schema.CreateDNSProvider())).
 | |
| 				Post("/", handler.CreateDNSProvider())
 | |
| 
 | |
| 			// Specific Item
 | |
| 			r.Route("/{providerID:[0-9]+}", func(r chi.Router) {
 | |
| 				r.With(middleware.Enforce(user.CapabilityDNSProvidersView)).
 | |
| 					Get("/{providerID:[0-9]+}", handler.GetDNSProvider())
 | |
| 				r.With(middleware.Enforce(user.CapabilityDNSProvidersManage)).Route("/", func(r chi.Router) {
 | |
| 					r.Delete("/", handler.DeleteDNSProvider())
 | |
| 					r.With(middleware.EnforceRequestSchema(schema.UpdateDNSProvider())).
 | |
| 						Put("/{providerID:[0-9]+}", handler.UpdateDNSProvider())
 | |
| 				})
 | |
| 			})
 | |
| 
 | |
| 			// List Acme DNS Providers
 | |
| 			r.With(middleware.Enforce(user.CapabilityDNSProvidersView)).Route("/acmesh", func(r chi.Router) {
 | |
| 				r.Get("/{acmeshID:[a-z0-9_]+}", handler.GetAcmeshProvider())
 | |
| 				r.Get("/", handler.GetAcmeshProviders())
 | |
| 			})
 | |
| 		})
 | |
| 
 | |
| 		// Certificate Authorities
 | |
| 		r.With(middleware.EnforceSetup(true)).Route("/certificate-authorities", func(r chi.Router) {
 | |
| 			// List
 | |
| 			r.With(middleware.Enforce(user.CapabilityCertificateAuthoritiesView), middleware.Filters(certificateauthority.GetFilterSchema())).
 | |
| 				Get("/", handler.GetCertificateAuthorities())
 | |
| 
 | |
| 			// Create
 | |
| 			r.With(middleware.Enforce(user.CapabilityCertificateAuthoritiesManage), middleware.EnforceRequestSchema(schema.CreateCertificateAuthority())).
 | |
| 				Post("/", handler.CreateCertificateAuthority())
 | |
| 
 | |
| 			// Specific Item
 | |
| 			r.Route("/{caID:[0-9]+}", func(r chi.Router) {
 | |
| 				r.With(middleware.Enforce(user.CapabilityCertificateAuthoritiesView)).
 | |
| 					Get("/", handler.GetCertificateAuthority())
 | |
| 				r.With(middleware.Enforce(user.CapabilityCertificateAuthoritiesManage)).Route("/", func(r chi.Router) {
 | |
| 					r.Delete("/{caID:[0-9]+}", handler.DeleteCertificateAuthority())
 | |
| 					r.With(middleware.EnforceRequestSchema(schema.UpdateCertificateAuthority())).
 | |
| 						Put("/{caID:[0-9]+}", handler.UpdateCertificateAuthority())
 | |
| 				})
 | |
| 			})
 | |
| 		})
 | |
| 
 | |
| 		// Certificates
 | |
| 		r.With(middleware.EnforceSetup(true)).Route("/certificates", func(r chi.Router) {
 | |
| 			// List
 | |
| 			r.With(middleware.Enforce(user.CapabilityCertificatesView), middleware.Filters(certificate.GetFilterSchema())).
 | |
| 				Get("/", handler.GetCertificates())
 | |
| 
 | |
| 			// Create
 | |
| 			r.With(middleware.Enforce(user.CapabilityCertificatesManage), middleware.EnforceRequestSchema(schema.CreateCertificate())).
 | |
| 				Post("/", handler.CreateCertificate())
 | |
| 
 | |
| 			// Specific Item
 | |
| 			r.Route("/{certificateID:[0-9]+}", func(r chi.Router) {
 | |
| 				r.With(middleware.Enforce(user.CapabilityCertificatesView)).
 | |
| 					Get("/", handler.GetCertificate())
 | |
| 				r.With(middleware.Enforce(user.CapabilityCertificatesManage)).Route("/", func(r chi.Router) {
 | |
| 					r.Delete("/", handler.DeleteCertificate())
 | |
| 					r.Put("/", handler.UpdateCertificate())
 | |
| 					// r.With(middleware.EnforceRequestSchema(schema.UpdateCertificate())).
 | |
| 					//     Put("/", handler.UpdateCertificate())
 | |
| 					r.Post("/renew", handler.RenewCertificate())
 | |
| 					r.Get("/download", handler.DownloadCertificate())
 | |
| 				})
 | |
| 			})
 | |
| 		})
 | |
| 
 | |
| 		// Hosts
 | |
| 		r.With(middleware.EnforceSetup(true)).Route("/hosts", func(r chi.Router) {
 | |
| 			// List
 | |
| 			r.With(middleware.Enforce(user.CapabilityHostsView), middleware.Filters(host.GetFilterSchema())).
 | |
| 				Get("/", handler.GetHosts())
 | |
| 
 | |
| 			// Create
 | |
| 			r.With(middleware.Enforce(user.CapabilityHostsManage), middleware.EnforceRequestSchema(schema.CreateHost())).
 | |
| 				Post("/", handler.CreateHost())
 | |
| 
 | |
| 			// Specific Item
 | |
| 			r.Route("/{hostID:[0-9]+}", func(r chi.Router) {
 | |
| 				r.With(middleware.Enforce(user.CapabilityHostsView)).
 | |
| 					Get("/", handler.GetHost())
 | |
| 				r.With(middleware.Enforce(user.CapabilityHostsManage)).Route("/", func(r chi.Router) {
 | |
| 					r.Delete("/", handler.DeleteHost())
 | |
| 					r.With(middleware.EnforceRequestSchema(schema.UpdateHost())).
 | |
| 						Put("/", handler.UpdateHost())
 | |
| 					r.Get("/nginx-config", handler.GetHostNginxConfig("json"))
 | |
| 					r.Get("/nginx-config.txt", handler.GetHostNginxConfig("text"))
 | |
| 				})
 | |
| 			})
 | |
| 		})
 | |
| 
 | |
| 		// Nginx Templates
 | |
| 		r.With(middleware.EnforceSetup(true)).Route("/nginx-templates", func(r chi.Router) {
 | |
| 			// List
 | |
| 			r.With(middleware.Enforce(user.CapabilityNginxTemplatesView), middleware.Filters(nginxtemplate.GetFilterSchema())).
 | |
| 				Get("/", handler.GetNginxTemplates())
 | |
| 
 | |
| 			// Create
 | |
| 			r.With(middleware.Enforce(user.CapabilityNginxTemplatesManage), middleware.EnforceRequestSchema(schema.CreateNginxTemplate())).
 | |
| 				Post("/", handler.CreateNginxTemplate())
 | |
| 
 | |
| 			// Specific Item
 | |
| 			r.Route("/{templateID:[0-9]+}", func(r chi.Router) {
 | |
| 				r.With(middleware.Enforce(user.CapabilityNginxTemplatesView)).
 | |
| 					Get("/", handler.GetNginxTemplates())
 | |
| 				r.With(middleware.Enforce(user.CapabilityHostsManage)).Route("/", func(r chi.Router) {
 | |
| 					r.Delete("/", handler.DeleteNginxTemplate())
 | |
| 					r.With(middleware.EnforceRequestSchema(schema.UpdateNginxTemplate())).
 | |
| 						Put("/", handler.UpdateNginxTemplate())
 | |
| 				})
 | |
| 			})
 | |
| 		})
 | |
| 
 | |
| 		// Streams
 | |
| 		r.With(middleware.EnforceSetup(true)).Route("/streams", func(r chi.Router) {
 | |
| 			// List
 | |
| 			r.With(middleware.Enforce(user.CapabilityStreamsView), middleware.Filters(stream.GetFilterSchema())).
 | |
| 				Get("/", handler.GetStreams())
 | |
| 
 | |
| 			// Create
 | |
| 			r.With(middleware.Enforce(user.CapabilityStreamsManage), middleware.EnforceRequestSchema(schema.CreateStream())).
 | |
| 				Post("/", handler.CreateStream())
 | |
| 
 | |
| 			// Specific Item
 | |
| 			r.Route("/{hostID:[0-9]+}", func(r chi.Router) {
 | |
| 				r.With(middleware.Enforce(user.CapabilityStreamsView)).
 | |
| 					Get("/", handler.GetStream())
 | |
| 				r.With(middleware.Enforce(user.CapabilityHostsManage)).Route("/", func(r chi.Router) {
 | |
| 					r.Delete("/", handler.DeleteStream())
 | |
| 					r.With(middleware.EnforceRequestSchema(schema.UpdateStream())).
 | |
| 						Put("/", handler.UpdateStream())
 | |
| 				})
 | |
| 			})
 | |
| 		})
 | |
| 
 | |
| 		// Upstreams
 | |
| 		r.With(middleware.EnforceSetup(true)).Route("/upstreams", func(r chi.Router) {
 | |
| 			// List
 | |
| 			r.With(middleware.Enforce(user.CapabilityHostsView), middleware.Filters(upstream.GetFilterSchema())).
 | |
| 				Get("/", handler.GetUpstreams())
 | |
| 
 | |
| 			// Create
 | |
| 			r.With(middleware.Enforce(user.CapabilityHostsManage), middleware.EnforceRequestSchema(schema.CreateUpstream())).
 | |
| 				Post("/", handler.CreateUpstream())
 | |
| 
 | |
| 			// Specific Item
 | |
| 			r.Route("/{upstreamID:[0-9]+}", func(r chi.Router) {
 | |
| 				r.With(middleware.Enforce(user.CapabilityHostsView)).
 | |
| 					Get("/", handler.GetUpstream())
 | |
| 				r.With(middleware.Enforce(user.CapabilityHostsManage)).Route("/", func(r chi.Router) {
 | |
| 					r.Delete("/", handler.DeleteUpstream())
 | |
| 					r.With(middleware.EnforceRequestSchema(schema.UpdateUpstream())).
 | |
| 						Put("/", handler.UpdateUpstream())
 | |
| 					r.Get("/nginx-config", handler.GetUpstreamNginxConfig("json"))
 | |
| 					r.Get("/nginx-config.txt", handler.GetUpstreamNginxConfig("text"))
 | |
| 				})
 | |
| 			})
 | |
| 		})
 | |
| 	})
 | |
| 
 | |
| 	return r
 | |
| }
 |