Refactor routing, changes API URLs (#1171)
* Make authentication part of the server, so it can be reused outside the Native API This commit has broken tests after a rebase * Serve frontend assets from `server`, and not from Native API * Change Native API URL * Fix auth tests * Refactor server authentication * Simplify authProvider, now subsonic token+salt comes from the server * Don't send JWT token to UI when authenticated via Request Header * Enable ReverseProxyWhitelist to be read from environment
This commit is contained in:
+24
-55
@@ -8,80 +8,51 @@ import (
|
||||
|
||||
"github.com/deluan/rest"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/httprate"
|
||||
"github.com/navidrome/navidrome/conf"
|
||||
"github.com/navidrome/navidrome/core"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/navidrome/navidrome/server"
|
||||
"github.com/navidrome/navidrome/server/events"
|
||||
"github.com/navidrome/navidrome/ui"
|
||||
)
|
||||
|
||||
type Router struct {
|
||||
http.Handler
|
||||
ds model.DataStore
|
||||
mux http.Handler
|
||||
broker events.Broker
|
||||
share core.Share
|
||||
}
|
||||
|
||||
func New(ds model.DataStore, broker events.Broker, share core.Share) *Router {
|
||||
return &Router{ds: ds, broker: broker, share: share}
|
||||
r := &Router{ds: ds, broker: broker, share: share}
|
||||
r.Handler = r.routes()
|
||||
return r
|
||||
}
|
||||
|
||||
func (app *Router) Setup(path string) {
|
||||
app.mux = app.routes(path)
|
||||
}
|
||||
|
||||
func (app *Router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
app.mux.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (app *Router) routes(path string) http.Handler {
|
||||
func (app *Router) routes() http.Handler {
|
||||
r := chi.NewRouter()
|
||||
|
||||
if conf.Server.AuthRequestLimit > 0 {
|
||||
log.Info("Login rate limit set", "requestLimit", conf.Server.AuthRequestLimit,
|
||||
"windowLength", conf.Server.AuthWindowLength)
|
||||
r.Use(server.Authenticator(app.ds))
|
||||
r.Use(server.JWTRefresher)
|
||||
app.R(r, "/user", model.User{}, true)
|
||||
app.R(r, "/song", model.MediaFile{}, true)
|
||||
app.R(r, "/album", model.Album{}, true)
|
||||
app.R(r, "/artist", model.Artist{}, true)
|
||||
app.R(r, "/player", model.Player{}, true)
|
||||
app.R(r, "/playlist", model.Playlist{}, true)
|
||||
app.R(r, "/transcoding", model.Transcoding{}, conf.Server.EnableTranscodingConfig)
|
||||
app.RX(r, "/share", app.share.NewRepository, true)
|
||||
app.RX(r, "/translation", newTranslationRepository, false)
|
||||
|
||||
rateLimiter := httprate.LimitByIP(conf.Server.AuthRequestLimit, conf.Server.AuthWindowLength)
|
||||
r.With(rateLimiter).Post("/login", Login(app.ds))
|
||||
} else {
|
||||
log.Warn("Login rate limit is disabled! Consider enabling it to be protected against brute-force attacks")
|
||||
app.addPlaylistTrackRoute(r)
|
||||
|
||||
r.Post("/login", Login(app.ds))
|
||||
}
|
||||
|
||||
r.Post("/createAdmin", CreateAdmin(app.ds))
|
||||
|
||||
r.Route("/api", func(r chi.Router) {
|
||||
r.Use(mapAuthHeader())
|
||||
r.Use(verifier())
|
||||
r.Use(authenticator(app.ds))
|
||||
app.R(r, "/user", model.User{}, true)
|
||||
app.R(r, "/song", model.MediaFile{}, true)
|
||||
app.R(r, "/album", model.Album{}, true)
|
||||
app.R(r, "/artist", model.Artist{}, true)
|
||||
app.R(r, "/player", model.Player{}, true)
|
||||
app.R(r, "/playlist", model.Playlist{}, true)
|
||||
app.R(r, "/transcoding", model.Transcoding{}, conf.Server.EnableTranscodingConfig)
|
||||
app.RX(r, "/share", app.share.NewRepository, true)
|
||||
app.RX(r, "/translation", newTranslationRepository, false)
|
||||
|
||||
app.addPlaylistTrackRoute(r)
|
||||
|
||||
// Keepalive endpoint to be used to keep the session valid (ex: while playing songs)
|
||||
r.Get("/keepalive/*", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte(`{"response":"ok", "id":"keepalive"}`))
|
||||
})
|
||||
|
||||
if conf.Server.DevActivityPanel {
|
||||
r.Handle("/events", app.broker)
|
||||
}
|
||||
// Keepalive endpoint to be used to keep the session valid (ex: while playing songs)
|
||||
r.Get("/keepalive/*", func(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte(`{"response":"ok", "id":"keepalive"}`))
|
||||
})
|
||||
|
||||
// Serve UI app assets
|
||||
r.Handle("/", serveIndex(app.ds, ui.Assets()))
|
||||
r.Handle("/*", http.StripPrefix(path, http.FileServer(http.FS(ui.Assets()))))
|
||||
if conf.Server.DevActivityPanel {
|
||||
r.Handle("/events", app.broker)
|
||||
}
|
||||
|
||||
return r
|
||||
}
|
||||
@@ -110,8 +81,6 @@ func (app *Router) RX(r chi.Router, pathPrefix string, constructor rest.Reposito
|
||||
})
|
||||
}
|
||||
|
||||
type restHandler = func(rest.RepositoryConstructor, ...rest.Logger) http.HandlerFunc
|
||||
|
||||
func (app *Router) addPlaylistTrackRoute(r chi.Router) {
|
||||
r.Route("/playlist/{playlistId}/tracks", func(r chi.Router) {
|
||||
r.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
Reference in New Issue
Block a user