Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tn/swap mux for chi #843

Merged
merged 13 commits into from
Jun 14, 2023
4 changes: 2 additions & 2 deletions backend/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ The details for this service are detailed in [pipeline readme](/backend/pipeline

## Development Overview

This project utilizes Golang 1.13 (with modules), interfaces with a MySQL database and leverages Gorilla Mux to help with routing. The project is testable via docker/docker-compose and is also deployed via docker.
This project utilizes Golang 1.20, interfaces with a MySQL database and leverages Chi to help with routing. The project is testable via docker/docker-compose and is also deployed via docker.

### Development Environment

Expand Down Expand Up @@ -598,7 +598,7 @@ The project contains various source code directories, effectively acting as a co
├── server # Route endpoint definitions and basic request validation
│ ├── dissectors # A builder-pattern like solution for interpreting request objects
│ ├── middleware # Middleware to assist with request handling
│ ├── remux # A rewrapping package for better ergonmics when utilizing gorilla mux
│ ├── remux # A rewrapping package for better ergonmics when utilizing chi
│ ├── api.go # Routes for the "API" / screenshot tool
│ └── web.go # Routes for the web service
├── services # Underlying service logic. Also includes a number of unit tests
Expand Down
4 changes: 2 additions & 2 deletions backend/authschemes/auth_scheme.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
package authschemes

import (
"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
)

// AuthScheme provides a small interface into interacting with the AShirt backend authentication.
Expand All @@ -23,7 +23,7 @@ import (
// system can use to register custom endpoints. Each router is prefixed with /auth/{name} (as
// determined by the Name() method)
type AuthScheme interface {
BindRoutes(*mux.Router, AShirtAuthBridge)
BindRoutes(chi.Router, AShirtAuthBridge)
Name() string
FriendlyName() string
Flags() []string
Expand Down
4 changes: 2 additions & 2 deletions backend/authschemes/localauth/local_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"fmt"
"net/http"

"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
"github.com/theparanoids/ashirt-server/backend"
"github.com/theparanoids/ashirt-server/backend/authschemes"
"github.com/theparanoids/ashirt-server/backend/authschemes/localauth/constants"
Expand Down Expand Up @@ -77,7 +77,7 @@ func (LocalAuthScheme) Type() string {
//
// In each case above, the actual action is deferred to the bridge connecting this auth scheme to
// the underlying system/database
func (p LocalAuthScheme) BindRoutes(r *mux.Router, bridge authschemes.AShirtAuthBridge) {
func (p LocalAuthScheme) BindRoutes(r chi.Router, bridge authschemes.AShirtAuthBridge) {
remux.Route(r, "POST", "/register", remux.JSONHandler(func(r *http.Request) (interface{}, error) {
if !p.RegistrationEnabled {
return nil, fmt.Errorf("registration is closed to users")
Expand Down
4 changes: 2 additions & 2 deletions backend/authschemes/oidcauth/oidc_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (
"net/http"

"github.com/coreos/go-oidc/v3/oidc"
"github.com/go-chi/chi/v5"
"github.com/gorilla/csrf"
"github.com/gorilla/mux"
"github.com/theparanoids/ashirt-server/backend"
"github.com/theparanoids/ashirt-server/backend/authschemes"
"github.com/theparanoids/ashirt-server/backend/config"
Expand Down Expand Up @@ -95,7 +95,7 @@ func (OIDCAuth) Flags() []string {
return []string{}
}

func (o OIDCAuth) BindRoutes(r *mux.Router, bridge authschemes.AShirtAuthBridge) {
func (o OIDCAuth) BindRoutes(r chi.Router, bridge authschemes.AShirtAuthBridge) {
remux.Route(r, "GET", "/login", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
o.redirectLogin(w, r, bridge, modeLogin)
}))
Expand Down
4 changes: 2 additions & 2 deletions backend/authschemes/recoveryauth/recovery_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
"strings"
"time"

"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
"github.com/theparanoids/ashirt-server/backend"
"github.com/theparanoids/ashirt-server/backend/authschemes"
"github.com/theparanoids/ashirt-server/backend/authschemes/recoveryauth/constants"
Expand Down Expand Up @@ -45,7 +45,7 @@ func (RecoveryAuthScheme) Type() string {
return constants.Code
}

func (p RecoveryAuthScheme) BindRoutes(r *mux.Router, bridge authschemes.AShirtAuthBridge) {
func (p RecoveryAuthScheme) BindRoutes(r chi.Router, bridge authschemes.AShirtAuthBridge) {
remux.Route(r, "POST", "/generate", remux.JSONHandler(func(r *http.Request) (interface{}, error) {
dr := remux.DissectJSONRequest(r)
userSlug := dr.FromBody("userSlug").Required().AsString()
Expand Down
4 changes: 2 additions & 2 deletions backend/authschemes/webauthn/webauthn.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"net/url"
"strings"

"github.com/gorilla/mux"
"github.com/go-chi/chi/v5"
"github.com/theparanoids/ashirt-server/backend"
"github.com/theparanoids/ashirt-server/backend/authschemes"
"github.com/theparanoids/ashirt-server/backend/authschemes/webauthn/constants"
Expand Down Expand Up @@ -93,7 +93,7 @@ func (a WebAuthn) Type() string {
return constants.Name
}

func (a WebAuthn) BindRoutes(r *mux.Router, bridge authschemes.AShirtAuthBridge) {
func (a WebAuthn) BindRoutes(r chi.Router, bridge authschemes.AShirtAuthBridge) {
remux.Route(r, "POST", "/register/begin", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
remux.JSONHandler(func(r *http.Request) (interface{}, error) {
// validate basic registration data
Expand Down
13 changes: 8 additions & 5 deletions backend/bin/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"errors"
"net/http"

"github.com/go-chi/chi/v5"
"github.com/theparanoids/ashirt-server/backend"
"github.com/theparanoids/ashirt-server/backend/config"
"github.com/theparanoids/ashirt-server/backend/config/confighelpers"
Expand Down Expand Up @@ -41,13 +42,15 @@ func main() {
logging.Fatal(logger, "msg", "store setup error", "error", err)
}

mux := http.NewServeMux()
s := chi.NewRouter()

mux.Handle("/api/", server.API(
db, contentStore, logger,
))
s.Route("/api", func(r chi.Router) {
server.API(r,
db, contentStore, logger,
)
})

logger.Log("msg", "starting API server", "port", config.Port())
serveErr := http.ListenAndServe(":"+config.Port(), mux)
serveErr := http.ListenAndServe(":"+config.Port(), s)
logging.Fatal(logger, "msg", "server shutting down", "err", serveErr)
}
37 changes: 22 additions & 15 deletions backend/bin/dev/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"os"
"time"

"github.com/go-chi/chi/v5"
"github.com/theparanoids/ashirt-server/backend"
"github.com/theparanoids/ashirt-server/backend/authschemes"
"github.com/theparanoids/ashirt-server/backend/authschemes/localauth"
Expand Down Expand Up @@ -117,22 +118,28 @@ func tryRunServer(logger logging.Logger) error {
logger.Log("msg", "No Emailer selected")
}

mux := http.NewServeMux()

mux.Handle("/web/", http.StripPrefix("/web", server.Web(
db, contentStore, &server.WebConfig{
CSRFAuthKey: []byte("DEVELOPMENT_CSRF_AUTH_KEY_SECRET"),
SessionStoreKey: []byte("DEVELOPMENT_SESSION_STORE_KEY_SECRET"),
UseSecureCookies: false,
AuthSchemes: schemes,
Logger: logger,
},
)))
mux.Handle("/api/", server.API(
jkennedyvz marked this conversation as resolved.
Show resolved Hide resolved
db, contentStore, logger,
))
r := chi.NewRouter()

r.Route("/web", func(r chi.Router) {
server.Web(r,
db, contentStore, &server.WebConfig{
CSRFAuthKey: []byte("DEVELOPMENT_CSRF_AUTH_KEY_SECRET"),
SessionStoreKey: []byte("DEVELOPMENT_SESSION_STORE_KEY_SECRET"),
UseSecureCookies: false,
AuthSchemes: schemes,
Logger: logger,
},
)
})

r.Route("/api", func(r chi.Router) {
server.API(r,
db, contentStore, logger,
)
})

logger.Log("port", config.Port(), "msg", "Now Serving")
return http.ListenAndServe(":"+config.Port(), mux)
return http.ListenAndServe(":"+config.Port(), r)
}

func handleAuthType(cfg config.AuthInstanceConfig) (authschemes.AuthScheme, error) {
Expand Down
25 changes: 14 additions & 11 deletions backend/bin/web/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net/http"
"os"

"github.com/go-chi/chi/v5"
"github.com/theparanoids/ashirt-server/backend"
"github.com/theparanoids/ashirt-server/backend/authschemes"
"github.com/theparanoids/ashirt-server/backend/authschemes/localauth"
Expand Down Expand Up @@ -86,20 +87,22 @@ func main() {
logger.Log("msg", "No Emailer selected")
}

mux := http.NewServeMux()
r := chi.NewRouter()

mux.Handle("/web/", http.StripPrefix("/web", server.Web(
db, contentStore, &server.WebConfig{
CSRFAuthKey: []byte(config.CSRFAuthKey()),
SessionStoreKey: []byte(config.SessionStoreKey()),
UseSecureCookies: true,
AuthSchemes: schemes,
Logger: logger,
},
)))
r.Route("/web", func(r chi.Router) {
server.Web(r,
db, contentStore, &server.WebConfig{
CSRFAuthKey: []byte(config.CSRFAuthKey()),
SessionStoreKey: []byte(config.SessionStoreKey()),
UseSecureCookies: true,
AuthSchemes: schemes,
Logger: logger,
},
)
})

logger.Log("msg", "starting Web server", "port", config.Port())
serveErr := http.ListenAndServe(":"+config.Port(), mux)
serveErr := http.ListenAndServe(":"+config.Port(), r)
logging.Fatal(logger, "msg", "server shutting down", "err", serveErr)
}

Expand Down
35 changes: 21 additions & 14 deletions backend/integration/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"testing"
"time"

"github.com/go-chi/chi/v5"
"github.com/stretchr/testify/require"
"github.com/theparanoids/ashirt-server/backend/authschemes"
"github.com/theparanoids/ashirt-server/backend/authschemes/localauth"
Expand All @@ -45,20 +46,26 @@ func NewTester(t *testing.T) *Tester {
require.NoError(t, err)
commonLogger := logging.SetupStdoutLogging()

s := http.NewServeMux()
s.Handle("/web/", http.StripPrefix("/web", server.Web(
db, contentStore, &server.WebConfig{
CSRFAuthKey: []byte("csrf-auth-key-for-integration-tests"),
SessionStoreKey: []byte("session-store-key-for-integration-tests"),
AuthSchemes: []authschemes.AuthScheme{localauth.LocalAuthScheme{
RegistrationEnabled: true,
}},
Logger: commonLogger,
},
)))
s.Handle("/api/", server.API(
db, contentStore, commonLogger,
))
s := chi.NewRouter()

s.Route("/web", func(r chi.Router) {
server.Web(r,
db, contentStore, &server.WebConfig{
CSRFAuthKey: []byte("csrf-auth-key-for-integration-tests"),
SessionStoreKey: []byte("session-store-key-for-integration-tests"),
AuthSchemes: []authschemes.AuthScheme{localauth.LocalAuthScheme{
RegistrationEnabled: true,
}},
Logger: commonLogger,
},
)
})

s.Route("/api", func(r chi.Router) {
server.API(r,
db, contentStore, commonLogger,
)
})

return &Tester{
t: t,
Expand Down
44 changes: 20 additions & 24 deletions backend/server/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,36 @@ import (
"net/http"
"time"

"github.com/go-chi/chi/v5"
"github.com/prometheus/client_golang/prometheus/promhttp"
"github.com/theparanoids/ashirt-server/backend"
"github.com/theparanoids/ashirt-server/backend/contentstore"
"github.com/theparanoids/ashirt-server/backend/database"
"github.com/theparanoids/ashirt-server/backend/dtos"
"github.com/theparanoids/ashirt-server/backend/logging"
"github.com/theparanoids/ashirt-server/backend/server/middleware"
"github.com/theparanoids/ashirt-server/backend/services"

"github.com/gorilla/mux"
"github.com/prometheus/client_golang/prometheus/promhttp"
)

func API(db *database.Connection, contentStore contentstore.Store, logger logging.Logger) http.Handler {
r := mux.NewRouter()
metricRouter := r.PathPrefix("").Subrouter()
metricRouter.Handle("/api/metrics", promhttp.Handler())

r.Use(middleware.LogRequests(logger))
r.Use(middleware.AuthenticateAppAndInjectCtx(db))

bindAPIRoutes(r, db, contentStore)
return r
func API(r chi.Router, db *database.Connection, contentStore contentstore.Store, logger logging.Logger) {
r.Handle("/metrics", promhttp.Handler())
r.Group(func(r chi.Router) {
r.Use(middleware.AuthenticateAppAndInjectCtx(db))
r.Use(middleware.LogRequests(logger))
bindAPIRoutes(r, db, contentStore)
})
}

func bindAPIRoutes(r *mux.Router, db *database.Connection, contentStore contentstore.Store) {
route(r, "GET", "/api/operations", jsonHandler(func(r *http.Request) (interface{}, error) {
func bindAPIRoutes(r chi.Router, db *database.Connection, contentStore contentstore.Store) {
route(r, "GET", "/operations", jsonHandler(func(r *http.Request) (interface{}, error) {
return services.ListOperations(r.Context(), db)
}))

route(r, "GET", "/api/checkconnection", jsonHandler(func(r *http.Request) (interface{}, error) {
route(r, "GET", "/checkconnection", jsonHandler(func(r *http.Request) (interface{}, error) {
return dtos.CheckConnection{Ok: true}, nil
}))

route(r, "POST", "/api/operations", jsonHandler(func(r *http.Request) (interface{}, error) {
route(r, "POST", "/operations", jsonHandler(func(r *http.Request) (interface{}, error) {
dr := dissectJSONRequest(r)
i := services.CreateOperationInput{
Slug: dr.FromBody("slug").Required().AsString(),
Expand All @@ -55,7 +51,7 @@ func bindAPIRoutes(r *mux.Router, db *database.Connection, contentStore contents
return services.CreateOperation(r.Context(), db, i)
}))

route(r, "GET", "/api/operations/{operation_slug}/evidence/{evidence_uuid}", jsonHandler(func(r *http.Request) (interface{}, error) {
route(r, "GET", "/operations/{operation_slug}/evidence/{evidence_uuid}", jsonHandler(func(r *http.Request) (interface{}, error) {
dr := dissectJSONRequest(r)
i := services.ReadEvidenceInput{
EvidenceUUID: dr.FromURL("evidence_uuid").Required().AsString(),
Expand All @@ -67,7 +63,7 @@ func bindAPIRoutes(r *mux.Router, db *database.Connection, contentStore contents
return services.ReadEvidence(r.Context(), db, contentStore, i)
}))

route(r, "GET", "/api/operations/{operation_slug}/evidence/{evidence_uuid}/{type:media|preview}", mediaHandler(func(r *http.Request) (io.Reader, error) {
route(r, "GET", "/operations/{operation_slug}/evidence/{evidence_uuid}/{type:media|preview}", mediaHandler(func(r *http.Request) (io.Reader, error) {
dr := dissectNoBodyRequest(r)
i := services.ReadEvidenceInput{
EvidenceUUID: dr.FromURL("evidence_uuid").Required().AsString(),
Expand All @@ -87,7 +83,7 @@ func bindAPIRoutes(r *mux.Router, db *database.Connection, contentStore contents
return evidence.Media, nil
}))

route(r, "POST", "/api/operations/{operation_slug}/evidence", jsonHandler(func(r *http.Request) (interface{}, error) {
route(r, "POST", "/operations/{operation_slug}/evidence", jsonHandler(func(r *http.Request) (interface{}, error) {
dr := dissectFormRequest(r)
i := services.CreateEvidenceInput{
Description: dr.FromBody("notes").Required().AsString(),
Expand All @@ -106,7 +102,7 @@ func bindAPIRoutes(r *mux.Router, db *database.Connection, contentStore contents
return services.CreateEvidence(r.Context(), db, contentStore, i)
}))

route(r, "PUT", "/api/operations/{operation_slug}/evidence/{evidence_uuid}", jsonHandler(func(r *http.Request) (interface{}, error) {
route(r, "PUT", "/operations/{operation_slug}/evidence/{evidence_uuid}", jsonHandler(func(r *http.Request) (interface{}, error) {
dr := dissectFormRequest(r)
i := services.UpdateEvidenceInput{
EvidenceUUID: dr.FromURL("evidence_uuid").Required().AsString(),
Expand All @@ -128,7 +124,7 @@ func bindAPIRoutes(r *mux.Router, db *database.Connection, contentStore contents
return nil, services.UpdateEvidence(r.Context(), db, contentStore, i)
}))

route(r, "PUT", "/api/operations/{operation_slug}/evidence/{evidence_uuid}/metadata", jsonHandler(func(r *http.Request) (interface{}, error) {
route(r, "PUT", "/operations/{operation_slug}/evidence/{evidence_uuid}/metadata", jsonHandler(func(r *http.Request) (interface{}, error) {
dr := dissectJSONRequest(r)
i := services.UpsertEvidenceMetadataInput{
EditEvidenceMetadataInput: services.EditEvidenceMetadataInput{
Expand All @@ -144,15 +140,15 @@ func bindAPIRoutes(r *mux.Router, db *database.Connection, contentStore contents
return nil, services.UpsertEvidenceMetadata(r.Context(), db, i)
}))

route(r, "GET", "/api/operations/{operation_slug}/tags", jsonHandler(func(r *http.Request) (interface{}, error) {
route(r, "GET", "/operations/{operation_slug}/tags", jsonHandler(func(r *http.Request) (interface{}, error) {
dr := dissectJSONRequest(r)
i := services.ListTagsForOperationInput{
OperationSlug: dr.FromURL("operation_slug").Required().AsString(),
}
return services.ListTagsForOperation(r.Context(), db, i)
}))

route(r, "POST", "/api/operations/{operation_slug}/tags", jsonHandler(func(r *http.Request) (interface{}, error) {
route(r, "POST", "/operations/{operation_slug}/tags", jsonHandler(func(r *http.Request) (interface{}, error) {
dr := dissectJSONRequest(r)
i := services.CreateTagInput{
Name: dr.FromBody("name").Required().AsString(),
Expand Down
Loading