Skip to content

Commit

Permalink
feat: implement relay endpoint (see #237)
Browse files Browse the repository at this point in the history
  • Loading branch information
muety committed Oct 11, 2021
1 parent 5394349 commit 8d073aa
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 0 deletions.
1 change: 1 addition & 0 deletions config.default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ security:
cookie_max_age: 172800
allow_signup: true
expose_metrics: false
enable_proxy: false # only intended for production instance at wakapi.dev

sentry:
dsn: # leave blank to disable sentry integration
Expand Down
1 change: 1 addition & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ type appConfig struct {
type securityConfig struct {
AllowSignup bool `yaml:"allow_signup" default:"true" env:"WAKAPI_ALLOW_SIGNUP"`
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))
PasswordSalt string `yaml:"password_salt" default:"" env:"WAKAPI_PASSWORD_SALT"`
InsecureCookies bool `yaml:"insecure_cookies" default:"false" env:"WAKAPI_INSECURE_COOKIES"`
Expand Down
5 changes: 5 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package main
import (
"embed"
"github.com/muety/wakapi/models"
"github.com/muety/wakapi/routes/relay"
"io/fs"
"log"
"net"
Expand Down Expand Up @@ -191,6 +192,9 @@ func main() {
loginHandler := routes.NewLoginHandler(userService, mailService)
imprintHandler := routes.NewImprintHandler(keyValueService)

// Other Handlers
relayHandler := relay.NewRelayHandler()

// Setup Routers
router := mux.NewRouter()
rootRouter := router.PathPrefix("/").Subrouter()
Expand Down Expand Up @@ -219,6 +223,7 @@ func main() {
imprintHandler.RegisterRoutes(rootRouter)
summaryHandler.RegisterRoutes(rootRouter)
settingsHandler.RegisterRoutes(rootRouter)
relayHandler.RegisterRoutes(rootRouter)

// API route registrations
summaryApiHandler.RegisterRoutes(apiRouter)
Expand Down
75 changes: 75 additions & 0 deletions routes/relay/relay.go
Original file line number Diff line number Diff line change
@@ -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)
}

0 comments on commit 8d073aa

Please sign in to comment.