mirror of
https://github.com/muety/wakapi.git
synced 2023-08-10 21:12:56 +03:00
feat: implement relay endpoint (see #237)
This commit is contained in:
parent
5394349c73
commit
8d073aaef2
@ -39,6 +39,7 @@ security:
|
|||||||
cookie_max_age: 172800
|
cookie_max_age: 172800
|
||||||
allow_signup: true
|
allow_signup: true
|
||||||
expose_metrics: false
|
expose_metrics: false
|
||||||
|
enable_proxy: false # only intended for production instance at wakapi.dev
|
||||||
|
|
||||||
sentry:
|
sentry:
|
||||||
dsn: # leave blank to disable sentry integration
|
dsn: # leave blank to disable sentry integration
|
||||||
|
@ -75,6 +75,7 @@ type appConfig struct {
|
|||||||
type securityConfig struct {
|
type securityConfig struct {
|
||||||
AllowSignup bool `yaml:"allow_signup" default:"true" env:"WAKAPI_ALLOW_SIGNUP"`
|
AllowSignup bool `yaml:"allow_signup" default:"true" env:"WAKAPI_ALLOW_SIGNUP"`
|
||||||
ExposeMetrics bool `yaml:"expose_metrics" default:"false" env:"WAKAPI_EXPOSE_METRICS"`
|
ExposeMetrics bool `yaml:"expose_metrics" default:"false" env:"WAKAPI_EXPOSE_METRICS"`
|
||||||
|
EnableProxy bool `yaml:"enable_proxy" default:"false" env:"WAKAPI_ENABLE_PROXY"` // only intended for production instance at wakapi.dev
|
||||||
// this is actually a pepper (https://en.wikipedia.org/wiki/Pepper_(cryptography))
|
// this is actually a pepper (https://en.wikipedia.org/wiki/Pepper_(cryptography))
|
||||||
PasswordSalt string `yaml:"password_salt" default:"" env:"WAKAPI_PASSWORD_SALT"`
|
PasswordSalt string `yaml:"password_salt" default:"" env:"WAKAPI_PASSWORD_SALT"`
|
||||||
InsecureCookies bool `yaml:"insecure_cookies" default:"false" env:"WAKAPI_INSECURE_COOKIES"`
|
InsecureCookies bool `yaml:"insecure_cookies" default:"false" env:"WAKAPI_INSECURE_COOKIES"`
|
||||||
|
5
main.go
5
main.go
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
"github.com/muety/wakapi/models"
|
"github.com/muety/wakapi/models"
|
||||||
|
"github.com/muety/wakapi/routes/relay"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
@ -191,6 +192,9 @@ func main() {
|
|||||||
loginHandler := routes.NewLoginHandler(userService, mailService)
|
loginHandler := routes.NewLoginHandler(userService, mailService)
|
||||||
imprintHandler := routes.NewImprintHandler(keyValueService)
|
imprintHandler := routes.NewImprintHandler(keyValueService)
|
||||||
|
|
||||||
|
// Other Handlers
|
||||||
|
relayHandler := relay.NewRelayHandler()
|
||||||
|
|
||||||
// Setup Routers
|
// Setup Routers
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
rootRouter := router.PathPrefix("/").Subrouter()
|
rootRouter := router.PathPrefix("/").Subrouter()
|
||||||
@ -219,6 +223,7 @@ func main() {
|
|||||||
imprintHandler.RegisterRoutes(rootRouter)
|
imprintHandler.RegisterRoutes(rootRouter)
|
||||||
summaryHandler.RegisterRoutes(rootRouter)
|
summaryHandler.RegisterRoutes(rootRouter)
|
||||||
settingsHandler.RegisterRoutes(rootRouter)
|
settingsHandler.RegisterRoutes(rootRouter)
|
||||||
|
relayHandler.RegisterRoutes(rootRouter)
|
||||||
|
|
||||||
// API route registrations
|
// API route registrations
|
||||||
summaryApiHandler.RegisterRoutes(apiRouter)
|
summaryApiHandler.RegisterRoutes(apiRouter)
|
||||||
|
75
routes/relay/relay.go
Normal file
75
routes/relay/relay.go
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
package relay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
conf "github.com/muety/wakapi/config"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
|
"net/url"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const targetUrlHeader = "X-Target-URL"
|
||||||
|
const pathMatcherPattern = `^/api/(heartbeat|heartbeats|summary|users|v1/users|compat/wakatime)`
|
||||||
|
|
||||||
|
type RelayHandler struct {
|
||||||
|
config *conf.Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewRelayHandler() *RelayHandler {
|
||||||
|
return &RelayHandler{
|
||||||
|
config: conf.Get(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type filteringMiddleware struct {
|
||||||
|
handler http.Handler
|
||||||
|
pathMatcher *regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFilteringMiddleware() func(http.Handler) http.Handler {
|
||||||
|
return func(h http.Handler) http.Handler {
|
||||||
|
return &filteringMiddleware{
|
||||||
|
handler: h,
|
||||||
|
pathMatcher: regexp.MustCompile(pathMatcherPattern),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *filteringMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
targetUrl, err := url.Parse(r.Header.Get(targetUrlHeader))
|
||||||
|
if err != nil || !m.pathMatcher.MatchString(targetUrl.Path) {
|
||||||
|
w.WriteHeader(http.StatusForbidden)
|
||||||
|
w.Write([]byte{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.handler.ServeHTTP(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RelayHandler) RegisterRoutes(router *mux.Router) {
|
||||||
|
if !h.config.Security.EnableProxy {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r := router.PathPrefix("/relay").Subrouter()
|
||||||
|
r.Use(newFilteringMiddleware())
|
||||||
|
r.Path("").HandlerFunc(h.Any)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RelayHandler) Any(w http.ResponseWriter, r *http.Request) {
|
||||||
|
targetUrl, err := url.Parse(r.Header.Get(targetUrlHeader))
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
|
w.Write([]byte{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
p := httputil.ReverseProxy{
|
||||||
|
Director: func(r *http.Request) {
|
||||||
|
r.URL = targetUrl
|
||||||
|
r.Host = targetUrl.Host
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
p.ServeHTTP(w, r)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user