mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
refactor: make each router handler register middleware on its own
This commit is contained in:
parent
8fed606e9b
commit
d1dc73b5e6
13
main.go
13
main.go
@ -126,13 +126,13 @@ func main() {
|
|||||||
|
|
||||||
// API Handlers
|
// API Handlers
|
||||||
healthApiHandler := api.NewHealthApiHandler(db)
|
healthApiHandler := api.NewHealthApiHandler(db)
|
||||||
heartbeatApiHandler := api.NewHeartbeatApiHandler(heartbeatService, languageMappingService)
|
heartbeatApiHandler := api.NewHeartbeatApiHandler(userService, heartbeatService, languageMappingService)
|
||||||
summaryApiHandler := api.NewSummaryApiHandler(summaryService)
|
summaryApiHandler := api.NewSummaryApiHandler(userService, summaryService)
|
||||||
|
|
||||||
// Compat Handlers
|
// Compat Handlers
|
||||||
wakatimeV1AllHandler := wtV1Routes.NewAllTimeHandler(summaryService)
|
wakatimeV1AllHandler := wtV1Routes.NewAllTimeHandler(userService, summaryService)
|
||||||
wakatimeV1SummariesHandler := wtV1Routes.NewSummariesHandler(summaryService)
|
wakatimeV1SummariesHandler := wtV1Routes.NewSummariesHandler(userService, summaryService)
|
||||||
wakatimeV1StatsHandler := wtV1Routes.NewStatsHandler(summaryService)
|
wakatimeV1StatsHandler := wtV1Routes.NewStatsHandler(userService, summaryService)
|
||||||
shieldV1BadgeHandler := shieldsV1Routes.NewBadgeHandler(summaryService, userService)
|
shieldV1BadgeHandler := shieldsV1Routes.NewBadgeHandler(summaryService, userService)
|
||||||
|
|
||||||
// MVC Handlers
|
// MVC Handlers
|
||||||
@ -152,11 +152,10 @@ func main() {
|
|||||||
recoveryMiddleware := handlers.RecoveryHandler()
|
recoveryMiddleware := handlers.RecoveryHandler()
|
||||||
loggingMiddleware := middlewares.NewLoggingMiddleware(log.New(os.Stdout, "", log.LstdFlags))
|
loggingMiddleware := middlewares.NewLoggingMiddleware(log.New(os.Stdout, "", log.LstdFlags))
|
||||||
corsMiddleware := handlers.CORS()
|
corsMiddleware := handlers.CORS()
|
||||||
authenticateMiddleware := middlewares.NewAuthenticateMiddleware(userService, []string{"/api/health", "/api/compat/shields/v1"}).Handler
|
|
||||||
|
|
||||||
// Router configs
|
// Router configs
|
||||||
router.Use(loggingMiddleware, recoveryMiddleware)
|
router.Use(loggingMiddleware, recoveryMiddleware)
|
||||||
apiRouter.Use(corsMiddleware, authenticateMiddleware)
|
apiRouter.Use(corsMiddleware)
|
||||||
|
|
||||||
// Route registrations
|
// Route registrations
|
||||||
homeHandler.RegisterRoutes(rootRouter)
|
homeHandler.RegisterRoutes(rootRouter)
|
||||||
|
@ -12,19 +12,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type AuthenticateMiddleware struct {
|
type AuthenticateMiddleware struct {
|
||||||
config *conf.Config
|
config *conf.Config
|
||||||
userSrvc services.IUserService
|
userSrvc services.IUserService
|
||||||
whitelistPaths []string
|
optionalForPaths []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAuthenticateMiddleware(userService services.IUserService, whitelistPaths []string) *AuthenticateMiddleware {
|
func NewAuthenticateMiddleware(userService services.IUserService) *AuthenticateMiddleware {
|
||||||
return &AuthenticateMiddleware{
|
return &AuthenticateMiddleware{
|
||||||
config: conf.Get(),
|
config: conf.Get(),
|
||||||
userSrvc: userService,
|
userSrvc: userService,
|
||||||
whitelistPaths: whitelistPaths,
|
optionalForPaths: []string{},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *AuthenticateMiddleware) WithOptionalFor(paths []string) {
|
||||||
|
m.optionalForPaths = paths
|
||||||
|
}
|
||||||
|
|
||||||
func (m *AuthenticateMiddleware) Handler(h http.Handler) http.Handler {
|
func (m *AuthenticateMiddleware) Handler(h http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
m.ServeHTTP(w, r, h.ServeHTTP)
|
m.ServeHTTP(w, r, h.ServeHTTP)
|
||||||
@ -32,13 +36,6 @@ func (m *AuthenticateMiddleware) Handler(h http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (m *AuthenticateMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
func (m *AuthenticateMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
|
||||||
for _, p := range m.whitelistPaths {
|
|
||||||
if strings.HasPrefix(r.URL.Path, p) || r.URL.Path == p {
|
|
||||||
next(w, r)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var user *models.User
|
var user *models.User
|
||||||
user, err := m.tryGetUserByCookie(r)
|
user, err := m.tryGetUserByCookie(r)
|
||||||
|
|
||||||
@ -46,7 +43,12 @@ func (m *AuthenticateMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Reques
|
|||||||
user, err = m.tryGetUserByApiKey(r)
|
user, err = m.tryGetUserByApiKey(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil || user == nil {
|
||||||
|
if m.isOptional(r.URL.Path) {
|
||||||
|
next(w, r)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if strings.HasPrefix(r.URL.Path, "/api") {
|
if strings.HasPrefix(r.URL.Path, "/api") {
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
} else {
|
} else {
|
||||||
@ -60,6 +62,15 @@ func (m *AuthenticateMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Reques
|
|||||||
next(w, r.WithContext(ctx))
|
next(w, r.WithContext(ctx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *AuthenticateMiddleware) isOptional(requestPath string) bool {
|
||||||
|
for _, p := range m.optionalForPaths {
|
||||||
|
if strings.HasPrefix(requestPath, p) || requestPath == p {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (m *AuthenticateMiddleware) tryGetUserByApiKey(r *http.Request) (*models.User, error) {
|
func (m *AuthenticateMiddleware) tryGetUserByApiKey(r *http.Request) (*models.User, error) {
|
||||||
key, err := utils.ExtractBearerAuth(r)
|
key, err := utils.ExtractBearerAuth(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/emvi/logbuch"
|
"github.com/emvi/logbuch"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
conf "github.com/muety/wakapi/config"
|
conf "github.com/muety/wakapi/config"
|
||||||
|
"github.com/muety/wakapi/middlewares"
|
||||||
customMiddleware "github.com/muety/wakapi/middlewares/custom"
|
customMiddleware "github.com/muety/wakapi/middlewares/custom"
|
||||||
"github.com/muety/wakapi/services"
|
"github.com/muety/wakapi/services"
|
||||||
"github.com/muety/wakapi/utils"
|
"github.com/muety/wakapi/utils"
|
||||||
@ -15,13 +16,15 @@ import (
|
|||||||
|
|
||||||
type HeartbeatApiHandler struct {
|
type HeartbeatApiHandler struct {
|
||||||
config *conf.Config
|
config *conf.Config
|
||||||
|
userSrvc services.IUserService
|
||||||
heartbeatSrvc services.IHeartbeatService
|
heartbeatSrvc services.IHeartbeatService
|
||||||
languageMappingSrvc services.ILanguageMappingService
|
languageMappingSrvc services.ILanguageMappingService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHeartbeatApiHandler(heartbeatService services.IHeartbeatService, languageMappingService services.ILanguageMappingService) *HeartbeatApiHandler {
|
func NewHeartbeatApiHandler(userService services.IUserService, heartbeatService services.IHeartbeatService, languageMappingService services.ILanguageMappingService) *HeartbeatApiHandler {
|
||||||
return &HeartbeatApiHandler{
|
return &HeartbeatApiHandler{
|
||||||
config: conf.Get(),
|
config: conf.Get(),
|
||||||
|
userSrvc: userService,
|
||||||
heartbeatSrvc: heartbeatService,
|
heartbeatSrvc: heartbeatService,
|
||||||
languageMappingSrvc: languageMappingService,
|
languageMappingSrvc: languageMappingService,
|
||||||
}
|
}
|
||||||
@ -34,6 +37,7 @@ type heartbeatResponseVm struct {
|
|||||||
func (h *HeartbeatApiHandler) RegisterRoutes(router *mux.Router) {
|
func (h *HeartbeatApiHandler) RegisterRoutes(router *mux.Router) {
|
||||||
r := router.PathPrefix("/heartbeat").Subrouter()
|
r := router.PathPrefix("/heartbeat").Subrouter()
|
||||||
r.Use(
|
r.Use(
|
||||||
|
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
|
||||||
customMiddleware.NewWakatimeRelayMiddleware().Handler,
|
customMiddleware.NewWakatimeRelayMiddleware().Handler,
|
||||||
)
|
)
|
||||||
r.Methods(http.MethodPost).HandlerFunc(h.Post)
|
r.Methods(http.MethodPost).HandlerFunc(h.Post)
|
||||||
|
@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
conf "github.com/muety/wakapi/config"
|
conf "github.com/muety/wakapi/config"
|
||||||
|
"github.com/muety/wakapi/middlewares"
|
||||||
su "github.com/muety/wakapi/routes/utils"
|
su "github.com/muety/wakapi/routes/utils"
|
||||||
"github.com/muety/wakapi/services"
|
"github.com/muety/wakapi/services"
|
||||||
"github.com/muety/wakapi/utils"
|
"github.com/muety/wakapi/utils"
|
||||||
@ -11,18 +12,23 @@ import (
|
|||||||
|
|
||||||
type SummaryApiHandler struct {
|
type SummaryApiHandler struct {
|
||||||
config *conf.Config
|
config *conf.Config
|
||||||
|
userSrvc services.IUserService
|
||||||
summarySrvc services.ISummaryService
|
summarySrvc services.ISummaryService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSummaryApiHandler(summaryService services.ISummaryService) *SummaryApiHandler {
|
func NewSummaryApiHandler(userService services.IUserService, summaryService services.ISummaryService) *SummaryApiHandler {
|
||||||
return &SummaryApiHandler{
|
return &SummaryApiHandler{
|
||||||
summarySrvc: summaryService,
|
summarySrvc: summaryService,
|
||||||
|
userSrvc: userService,
|
||||||
config: conf.Get(),
|
config: conf.Get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SummaryApiHandler) RegisterRoutes(router *mux.Router) {
|
func (h *SummaryApiHandler) RegisterRoutes(router *mux.Router) {
|
||||||
r := router.PathPrefix("/summary").Subrouter()
|
r := router.PathPrefix("/summary").Subrouter()
|
||||||
|
r.Use(
|
||||||
|
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
|
||||||
|
)
|
||||||
r.Methods(http.MethodGet).HandlerFunc(h.Get)
|
r.Methods(http.MethodGet).HandlerFunc(h.Get)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ func NewBadgeHandler(summaryService services.ISummaryService, userService servic
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *BadgeHandler) RegisterRoutes(router *mux.Router) {
|
func (h *BadgeHandler) RegisterRoutes(router *mux.Router) {
|
||||||
|
// no auth middleware here, handler itself resolves the user
|
||||||
r := router.PathPrefix("/shields/v1/{user}").Subrouter()
|
r := router.PathPrefix("/shields/v1/{user}").Subrouter()
|
||||||
r.Methods(http.MethodGet).HandlerFunc(h.Get)
|
r.Methods(http.MethodGet).HandlerFunc(h.Get)
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package v1
|
|||||||
import (
|
import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
conf "github.com/muety/wakapi/config"
|
conf "github.com/muety/wakapi/config"
|
||||||
|
"github.com/muety/wakapi/middlewares"
|
||||||
"github.com/muety/wakapi/models"
|
"github.com/muety/wakapi/models"
|
||||||
v1 "github.com/muety/wakapi/models/compat/wakatime/v1"
|
v1 "github.com/muety/wakapi/models/compat/wakatime/v1"
|
||||||
"github.com/muety/wakapi/services"
|
"github.com/muety/wakapi/services"
|
||||||
@ -14,18 +15,24 @@ import (
|
|||||||
|
|
||||||
type AllTimeHandler struct {
|
type AllTimeHandler struct {
|
||||||
config *conf.Config
|
config *conf.Config
|
||||||
|
userSrvc services.IUserService
|
||||||
summarySrvc services.ISummaryService
|
summarySrvc services.ISummaryService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAllTimeHandler(summaryService services.ISummaryService) *AllTimeHandler {
|
func NewAllTimeHandler(userService services.IUserService, summaryService services.ISummaryService) *AllTimeHandler {
|
||||||
return &AllTimeHandler{
|
return &AllTimeHandler{
|
||||||
|
userSrvc: userService,
|
||||||
summarySrvc: summaryService,
|
summarySrvc: summaryService,
|
||||||
config: conf.Get(),
|
config: conf.Get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *AllTimeHandler) RegisterRoutes(router *mux.Router) {
|
func (h *AllTimeHandler) RegisterRoutes(router *mux.Router) {
|
||||||
router.Path("/wakatime/v1/users/{user}/all_time_since_today").Methods(http.MethodGet).HandlerFunc(h.Get)
|
r := router.PathPrefix("/wakatime/v1/users/{user}/all_time_since_today").Subrouter()
|
||||||
|
r.Use(
|
||||||
|
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
|
||||||
|
)
|
||||||
|
r.Methods(http.MethodGet).HandlerFunc(h.Get)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *AllTimeHandler) Get(w http.ResponseWriter, r *http.Request) {
|
func (h *AllTimeHandler) Get(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
conf "github.com/muety/wakapi/config"
|
conf "github.com/muety/wakapi/config"
|
||||||
|
"github.com/muety/wakapi/middlewares"
|
||||||
"github.com/muety/wakapi/models"
|
"github.com/muety/wakapi/models"
|
||||||
v1 "github.com/muety/wakapi/models/compat/wakatime/v1"
|
v1 "github.com/muety/wakapi/models/compat/wakatime/v1"
|
||||||
"github.com/muety/wakapi/services"
|
"github.com/muety/wakapi/services"
|
||||||
@ -14,18 +15,24 @@ import (
|
|||||||
|
|
||||||
type StatsHandler struct {
|
type StatsHandler struct {
|
||||||
config *conf.Config
|
config *conf.Config
|
||||||
|
userSrvc services.IUserService
|
||||||
summarySrvc services.ISummaryService
|
summarySrvc services.ISummaryService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStatsHandler(summaryService services.ISummaryService) *StatsHandler {
|
func NewStatsHandler(userService services.IUserService, summaryService services.ISummaryService) *StatsHandler {
|
||||||
return &StatsHandler{
|
return &StatsHandler{
|
||||||
|
userSrvc: userService,
|
||||||
summarySrvc: summaryService,
|
summarySrvc: summaryService,
|
||||||
config: conf.Get(),
|
config: conf.Get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *StatsHandler) RegisterRoutes(router *mux.Router) {
|
func (h *StatsHandler) RegisterRoutes(router *mux.Router) {
|
||||||
router.Path("/wakatime/v1/users/{user}/stats/{range}").Methods(http.MethodGet).HandlerFunc(h.Get)
|
r := router.PathPrefix("/wakatime/v1/users/{user}/stats/{range}").Subrouter()
|
||||||
|
r.Use(
|
||||||
|
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
|
||||||
|
)
|
||||||
|
r.Methods(http.MethodGet).HandlerFunc(h.Get)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: support filtering (requires https://github.com/muety/wakapi/issues/108)
|
// TODO: support filtering (requires https://github.com/muety/wakapi/issues/108)
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
conf "github.com/muety/wakapi/config"
|
conf "github.com/muety/wakapi/config"
|
||||||
|
"github.com/muety/wakapi/middlewares"
|
||||||
"github.com/muety/wakapi/models"
|
"github.com/muety/wakapi/models"
|
||||||
v1 "github.com/muety/wakapi/models/compat/wakatime/v1"
|
v1 "github.com/muety/wakapi/models/compat/wakatime/v1"
|
||||||
"github.com/muety/wakapi/services"
|
"github.com/muety/wakapi/services"
|
||||||
@ -15,18 +16,24 @@ import (
|
|||||||
|
|
||||||
type SummariesHandler struct {
|
type SummariesHandler struct {
|
||||||
config *conf.Config
|
config *conf.Config
|
||||||
|
userSrvc services.IUserService
|
||||||
summarySrvc services.ISummaryService
|
summarySrvc services.ISummaryService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewSummariesHandler(summaryService services.ISummaryService) *SummariesHandler {
|
func NewSummariesHandler(userService services.IUserService, summaryService services.ISummaryService) *SummariesHandler {
|
||||||
return &SummariesHandler{
|
return &SummariesHandler{
|
||||||
|
userSrvc: userService,
|
||||||
summarySrvc: summaryService,
|
summarySrvc: summaryService,
|
||||||
config: conf.Get(),
|
config: conf.Get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *SummariesHandler) RegisterRoutes(router *mux.Router) {
|
func (h *SummariesHandler) RegisterRoutes(router *mux.Router) {
|
||||||
router.Path("/wakatime/v1/users/{user}/summaries").Methods(http.MethodGet).HandlerFunc(h.Get)
|
r := router.PathPrefix("/wakatime/v1/users/{user}/summaries").Subrouter()
|
||||||
|
r.Use(
|
||||||
|
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
|
||||||
|
)
|
||||||
|
r.Methods(http.MethodGet).HandlerFunc(h.Get)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Support parameters: project, branches, timeout, writes_only, timezone
|
// TODO: Support parameters: project, branches, timeout, writes_only, timezone
|
||||||
|
@ -57,7 +57,7 @@ func NewSettingsHandler(
|
|||||||
func (h *SettingsHandler) RegisterRoutes(router *mux.Router) {
|
func (h *SettingsHandler) RegisterRoutes(router *mux.Router) {
|
||||||
r := router.PathPrefix("/settings").Subrouter()
|
r := router.PathPrefix("/settings").Subrouter()
|
||||||
r.Use(
|
r.Use(
|
||||||
middlewares.NewAuthenticateMiddleware(h.userSrvc, []string{}).Handler,
|
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
|
||||||
)
|
)
|
||||||
r.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
|
r.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
|
||||||
r.Methods(http.MethodPost).HandlerFunc(h.PostIndex)
|
r.Methods(http.MethodPost).HandlerFunc(h.PostIndex)
|
||||||
|
@ -29,7 +29,7 @@ func NewSummaryHandler(summaryService services.ISummaryService, userService serv
|
|||||||
func (h *SummaryHandler) RegisterRoutes(router *mux.Router) {
|
func (h *SummaryHandler) RegisterRoutes(router *mux.Router) {
|
||||||
r := router.PathPrefix("/summary").Subrouter()
|
r := router.PathPrefix("/summary").Subrouter()
|
||||||
r.Use(
|
r.Use(
|
||||||
middlewares.NewAuthenticateMiddleware(h.userSrvc, []string{}).Handler,
|
middlewares.NewAuthenticateMiddleware(h.userSrvc).Handler,
|
||||||
)
|
)
|
||||||
r.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
|
r.Methods(http.MethodGet).HandlerFunc(h.GetIndex)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user