control: Generalize cookie and csrf handling
This commit is contained in:
parent
eb17dbe33f
commit
34bdb3cf24
15 changed files with 122 additions and 44 deletions
|
|
@ -36,19 +36,24 @@ var (
|
|||
_ component.Routeable = (*Admin)(nil)
|
||||
)
|
||||
|
||||
func (*Admin) Routes() []string { return []string{"/admin/"} }
|
||||
func (admin *Admin) Routes() component.Routes {
|
||||
return component.Routes{
|
||||
Paths: []string{"/admin/"},
|
||||
CSRF: true,
|
||||
Decorator: admin.Dependencies.Auth.Require(auth.Admin),
|
||||
}
|
||||
}
|
||||
|
||||
func (admin *Admin) HandleRoute(ctx context.Context, route string) (handler http.Handler, err error) {
|
||||
|
||||
router := httprouter.New()
|
||||
|
||||
{
|
||||
socket := &httpx.WebSocket{
|
||||
handler = &httpx.WebSocket{
|
||||
Context: ctx,
|
||||
Fallback: router,
|
||||
Handler: admin.serveSocket,
|
||||
}
|
||||
handler = admin.Dependencies.Auth.Protect(socket, auth.Admin)
|
||||
}
|
||||
|
||||
// handle everything
|
||||
|
|
|
|||
|
|
@ -64,8 +64,6 @@ func (admin *Admin) createUser(ctx context.Context) http.Handler {
|
|||
},
|
||||
FieldTemplate: httpx.PureCSSFieldTemplate,
|
||||
|
||||
CSRF: true,
|
||||
|
||||
RenderTemplate: userCreateTemplate,
|
||||
|
||||
Validate: func(r *http.Request, values map[string]string) (cu createUserResult, err error) {
|
||||
|
|
|
|||
14
internal/dis/component/control/cookies.go
Normal file
14
internal/dis/component/control/cookies.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package control
|
||||
|
||||
// CSRFCookie, CSRFCookieField, SessionCookie and SessionUserKey
|
||||
// hold the names of the cookies and fields used for specific cookies.
|
||||
//
|
||||
// These are intentionally kept short to conserve bandwidth.
|
||||
const (
|
||||
CSRFCookie = "F" // CSRF cookie sent on a lot of requests
|
||||
CSRFCookieField = "@" // form field name __should not be used by anything else__
|
||||
// to pay respect
|
||||
|
||||
SessionCookie = "x" // name of the cookie to use ; to doubt
|
||||
SessionUserKey = "@" // key within the session data to hold the username
|
||||
)
|
||||
|
|
@ -25,7 +25,12 @@ var (
|
|||
_ component.Routeable = (*Home)(nil)
|
||||
)
|
||||
|
||||
func (*Home) Routes() []string { return []string{"/"} }
|
||||
func (*Home) Routes() component.Routes {
|
||||
return component.Routes{
|
||||
Paths: []string{"/"},
|
||||
CSRF: false,
|
||||
}
|
||||
}
|
||||
|
||||
func (home *Home) HandleRoute(ctx context.Context, route string) (http.Handler, error) {
|
||||
return home, nil
|
||||
|
|
|
|||
|
|
@ -18,28 +18,38 @@ func (control *Control) Server(ctx context.Context, progress io.Writer) (http.Ha
|
|||
// create a new mux
|
||||
mux := http.NewServeMux()
|
||||
|
||||
// add all the servable routes!
|
||||
// create a csrf protector
|
||||
csrfProtector := control.CSRF()
|
||||
|
||||
// iterate over all the handler
|
||||
for _, s := range control.Dependencies.Routeables {
|
||||
for _, route := range s.Routes() {
|
||||
zerolog.Ctx(ctx).Info().Str("component", s.Name()).Str("route", route).Msg("mounting route")
|
||||
handler, err := s.HandleRoute(ctx, route)
|
||||
routes := s.Routes()
|
||||
zerolog.Ctx(ctx).Info().Str("component", s.Name()).Strs("paths", routes.Paths).Bool("csrf", routes.CSRF).Bool("decorator", routes.Decorator != nil).Msg("mounting route")
|
||||
|
||||
for _, path := range routes.Paths {
|
||||
handler, err := s.HandleRoute(ctx, path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
mux.Handle(route, handler)
|
||||
mux.Handle(path, routes.Decorate(handler, csrfProtector))
|
||||
}
|
||||
}
|
||||
|
||||
return func(handler http.HandlerFunc) http.Handler {
|
||||
// setup a csrf protector for everything with POST
|
||||
var opts []csrf.Option
|
||||
if !control.Config.HTTPSEnabled() {
|
||||
opts = append(opts, csrf.Secure(false))
|
||||
}
|
||||
opts = append(opts, csrf.SameSite(csrf.SameSiteStrictMode))
|
||||
return csrf.Protect(control.Config.CSRFSecret(), opts...)(handler)
|
||||
}(func(w http.ResponseWriter, r *http.Request) {
|
||||
// apply the given context function
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
r = r.WithContext(cancel.ValuesOf(r.Context(), ctx))
|
||||
mux.ServeHTTP(w, r)
|
||||
}), nil
|
||||
}
|
||||
|
||||
// CSRF returns a CSRF handler for the given function
|
||||
func (control *Control) CSRF() func(http.Handler) http.Handler {
|
||||
var opts []csrf.Option
|
||||
if !control.Config.HTTPSEnabled() {
|
||||
opts = append(opts, csrf.Secure(false))
|
||||
}
|
||||
opts = append(opts, csrf.SameSite(csrf.SameSiteStrictMode))
|
||||
opts = append(opts, csrf.CookieName(CSRFCookie))
|
||||
opts = append(opts, csrf.FieldName(CSRFCookieField))
|
||||
return csrf.Protect(control.Config.CSRFSecret(), opts...)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,12 @@ var (
|
|||
_ component.Routeable = (*Static)(nil)
|
||||
)
|
||||
|
||||
func (*Static) Routes() []string { return []string{"/static/"} }
|
||||
func (*Static) Routes() component.Routes {
|
||||
return component.Routes{
|
||||
Paths: []string{"/static/"},
|
||||
CSRF: false,
|
||||
}
|
||||
}
|
||||
|
||||
//go:embed dist
|
||||
var staticFS embed.FS
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue