2
0

router.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. package router
  2. import (
  3. "net/http"
  4. "github.com/go-chi/chi"
  5. "github.com/porter-dev/porter/api/server/authn"
  6. "github.com/porter-dev/porter/api/server/authz"
  7. "github.com/porter-dev/porter/api/server/shared"
  8. "github.com/porter-dev/porter/api/types"
  9. )
  10. func NewAPIRouter(config *shared.Config) *chi.Mux {
  11. r := chi.NewRouter()
  12. // set the content type for all API endpoints
  13. r.Use(ContentTypeJSON)
  14. endpointFactory := shared.NewAPIObjectEndpointFactory(config)
  15. baseRegisterer := NewBaseRegisterer()
  16. projRegisterer := NewProjectScopedRegisterer()
  17. userRegisterer := NewUserScopedRegisterer(projRegisterer)
  18. r.Route("/api", func(r chi.Router) {
  19. baseRoutes := baseRegisterer.GetRoutes(
  20. r,
  21. config,
  22. &types.Path{
  23. RelativePath: "",
  24. },
  25. endpointFactory,
  26. )
  27. userRoutes := userRegisterer.GetRoutes(
  28. r,
  29. config,
  30. &types.Path{
  31. RelativePath: "",
  32. },
  33. endpointFactory,
  34. userRegisterer.Children...,
  35. )
  36. routes := append(baseRoutes, userRoutes...)
  37. registerRoutes(config, routes)
  38. })
  39. return r
  40. }
  41. type Route struct {
  42. Endpoint *shared.APIEndpoint
  43. Handler http.Handler
  44. Router chi.Router
  45. }
  46. type Registerer struct {
  47. GetRoutes func(
  48. r chi.Router,
  49. config *shared.Config,
  50. basePath *types.Path,
  51. factory shared.APIEndpointFactory,
  52. children ...*Registerer,
  53. ) []*Route
  54. Children []*Registerer
  55. }
  56. func registerRoutes(config *shared.Config, routes []*Route) {
  57. // Create a new "user-scoped" factory which will create a new user-scoped request
  58. // after authentication. Each subsequent http.Handler can lookup the user in context.
  59. authNFactory := authn.NewAuthNFactory(config)
  60. // Create a new "project-scoped" factory which will create a new project-scoped request
  61. // after authorization. Each subsequent http.Handler can lookup the project in context.
  62. projFactory := authz.NewProjectScopedFactory(config)
  63. for _, route := range routes {
  64. atomicGroup := route.Router.Group(nil)
  65. for _, scope := range route.Endpoint.Metadata.Scopes {
  66. switch scope {
  67. case types.UserScope:
  68. // if the endpoint should redirect when authn fails, attach redirect handler
  69. if route.Endpoint.Metadata.ShouldRedirect {
  70. atomicGroup.Use(authNFactory.NewAuthenticatedWithRedirect)
  71. } else {
  72. atomicGroup.Use(authNFactory.NewAuthenticated)
  73. }
  74. case types.ProjectScope:
  75. atomicGroup.Use(projFactory.Middleware)
  76. }
  77. }
  78. atomicGroup.Method(
  79. string(route.Endpoint.Metadata.Method),
  80. route.Endpoint.Metadata.Path.RelativePath,
  81. route.Handler,
  82. )
  83. }
  84. }
  85. // ContentTypeJSON sets the content type for requests to application/json
  86. func ContentTypeJSON(next http.Handler) http.Handler {
  87. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  88. w.Header().Set("Content-Type", "application/json;charset=utf8")
  89. next.ServeHTTP(w, r)
  90. })
  91. }