diff --git a/cmd/gotosocial/action/server/server.go b/cmd/gotosocial/action/server/server.go index 5bdd3e33f..f831d6eba 100644 --- a/cmd/gotosocial/action/server/server.go +++ b/cmd/gotosocial/action/server/server.go @@ -191,7 +191,7 @@ var Start action.GTSAction = func(ctx context.Context) error { wellKnownModule = api.NewWellKnown(processor) // .well-known endpoints nodeInfoModule = api.NewNodeInfo(processor) // nodeinfo endpoint activityPubModule = api.NewActivityPub(dbService, processor) // ActivityPub endpoints - webModule = web.New(processor) // web pages + user profiles + settings panels etc + webModule = web.New(dbService, processor) // web pages + user profiles + settings panels etc ) // create required middleware diff --git a/cmd/gotosocial/action/testrig/testrig.go b/cmd/gotosocial/action/testrig/testrig.go index 8efc225a5..e3e907442 100644 --- a/cmd/gotosocial/action/testrig/testrig.go +++ b/cmd/gotosocial/action/testrig/testrig.go @@ -129,7 +129,7 @@ var Start action.GTSAction = func(ctx context.Context) error { wellKnownModule = api.NewWellKnown(processor) // .well-known endpoints nodeInfoModule = api.NewNodeInfo(processor) // nodeinfo endpoint activityPubModule = api.NewActivityPub(dbService, processor) // ActivityPub endpoints - webModule = web.New(processor) // web pages + user profiles + settings panels etc + webModule = web.New(dbService, processor) // web pages + user profiles + settings panels etc ) // these should be routed in order diff --git a/internal/web/web.go b/internal/web/web.go index f4529286a..0fc1644c8 100644 --- a/internal/web/web.go +++ b/internal/web/web.go @@ -19,13 +19,17 @@ package web import ( + "context" "net/http" + "net/url" "path/filepath" "codeberg.org/gruf/go-cache/v3" "github.com/gin-gonic/gin" "github.com/superseriousbusiness/gotosocial/internal/config" + "github.com/superseriousbusiness/gotosocial/internal/db" "github.com/superseriousbusiness/gotosocial/internal/log" + "github.com/superseriousbusiness/gotosocial/internal/middleware" "github.com/superseriousbusiness/gotosocial/internal/processing" "github.com/superseriousbusiness/gotosocial/internal/router" "github.com/superseriousbusiness/gotosocial/internal/uris" @@ -33,10 +37,10 @@ import ( const ( confirmEmailPath = "/" + uris.ConfirmEmailPath - profilePath = "/@:" + usernameKey - customCSSPath = profilePath + "/custom.css" - rssFeedPath = profilePath + "/feed.rss" - statusPath = profilePath + "/statuses/:" + statusIDKey + profileGroupPath = "/@:" + usernameKey + statusPath = "/statuses/:" + statusIDKey // leave out the '/@:username' prefix as this will be served within the profile group + customCSSPath = profileGroupPath + "/custom.css" + rssFeedPath = profileGroupPath + "/feed.rss" assetsPathPrefix = "/assets" distPathPrefix = assetsPathPrefix + "/dist" settingsPathPrefix = "/settings" @@ -57,55 +61,52 @@ const ( ) type Module struct { - processor processing.Processor - eTagCache cache.Cache[string, eTagCacheEntry] + processor processing.Processor + eTagCache cache.Cache[string, eTagCacheEntry] + isURIBlocked func(context.Context, *url.URL) (bool, db.Error) } -func New(processor processing.Processor) *Module { +func New(db db.DB, processor processing.Processor) *Module { return &Module{ - processor: processor, - eTagCache: newETagCache(), + processor: processor, + eTagCache: newETagCache(), + isURIBlocked: db.IsURIBlocked, } } func (m *Module) Route(r router.Router, mi ...gin.HandlerFunc) { - // serve static files from assets dir at /assets - assetsGroup := r.AttachGroup(assetsPathPrefix) + // Group all static files from assets dir at /assets, + // so that they can use the same cache control middleware. webAssetsAbsFilePath, err := filepath.Abs(config.GetWebAssetBaseDir()) if err != nil { log.Panicf("error getting absolute path of assets dir: %s", err) } - fs := fileSystem{http.Dir(webAssetsAbsFilePath)} - - // use the cache middleware on all handlers in this group + assetsGroup := r.AttachGroup(assetsPathPrefix) assetsGroup.Use(m.assetsCacheControlMiddleware(fs)) assetsGroup.Use(mi...) - - // serve static file system in the root of this group, - // will end up being something like "/assets/" assetsGroup.StaticFS("/", fs) - /* - Attach individual web handlers which require no specific middlewares - */ + // handlers that serve profiles and statuses should use the SignatureCheck + // middleware, so that requests with content-type application/activity+json + // can still be served + profileGroup := r.AttachGroup(profileGroupPath) + profileGroup.Use(mi...) + profileGroup.Use(middleware.SignatureCheck(m.isURIBlocked), middleware.CacheControl("no-store")) + profileGroup.Handle(http.MethodGet, "", m.profileGETHandler) // use empty path here since it's the base of the group + profileGroup.Handle(http.MethodGet, statusPath, m.threadGETHandler) + // Attach individual web handlers which require no specific middlewares r.AttachHandler(http.MethodGet, "/", m.baseHandler) // front-page r.AttachHandler(http.MethodGet, settingsPathPrefix, m.SettingsPanelHandler) r.AttachHandler(http.MethodGet, settingsPanelGlob, m.SettingsPanelHandler) - r.AttachHandler(http.MethodGet, profilePath, m.profileGETHandler) r.AttachHandler(http.MethodGet, customCSSPath, m.customCSSGETHandler) r.AttachHandler(http.MethodGet, rssFeedPath, m.rssFeedGETHandler) - r.AttachHandler(http.MethodGet, statusPath, m.threadGETHandler) r.AttachHandler(http.MethodGet, confirmEmailPath, m.confirmEmailGETHandler) r.AttachHandler(http.MethodGet, robotsPath, m.robotsGETHandler) - r.AttachHandler(http.MethodGet, domainBlockListPath, m.domainBlockListGETHandler) - /* - Attach redirects from old endpoints to current ones for backwards compatibility - */ - + // Attach redirects from old endpoints to current ones for backwards compatibility r.AttachHandler(http.MethodGet, "/auth/edit", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, userPanelPath) }) r.AttachHandler(http.MethodGet, "/user", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, userPanelPath) }) r.AttachHandler(http.MethodGet, "/admin", func(c *gin.Context) { c.Redirect(http.StatusMovedPermanently, adminPanelPath) })